corp-app/CORP-MAUI/Pages/EmployeesPage.xaml.cs

279 lines
11 KiB
C#
Raw Permalink 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.

using System.Collections.ObjectModel;
using System.Diagnostics;
using CORP_MAUI.Models;
using Microsoft.Maui.Controls; // для TapGestureRecognizer и BindableObject
namespace CORP_MAUI.Pages;
public partial class EmployeesPage : ContentPage
{
private readonly ObservableCollection<User> _employees;
private List<User> _allEmployees = new();
public EmployeesPage()
{
try
{
Trace.WriteLine("=== EMPLOYEESPAGE CONSTRUCTOR START ===");
Trace.WriteLine("[EmployeesPage] >>> Вызов InitializeComponent");
InitializeComponent();
Trace.WriteLine("[EmployeesPage] >>> InitializeComponent завершен");
_employees = new ObservableCollection<User>();
EmployeesCollectionView.ItemsSource = _employees;
Trace.WriteLine("[EmployeesPage] >>> Подписка на UserStatusChanged");
// Подписываемся на изменения статуса пользователей
ServiceProvider.WebSocketService.UserStatusChanged += OnUserStatusChanged;
Trace.WriteLine("[EmployeesPage] >>> Запуск LoadEmployeesAsync");
// Загружаем сотрудников
_ = LoadEmployeesAsync();
Trace.WriteLine("=== EMPLOYEESPAGE CONSTRUCTOR END ===");
}
catch (Exception ex)
{
Trace.WriteLine("=== EMPLOYEESPAGE CONSTRUCTOR ERROR ===");
Trace.WriteLine($"[EmployeesPage] ❌ Тип ошибки: {ex.GetType().FullName}");
Trace.WriteLine($"[EmployeesPage] ❌ Сообщение: {ex.Message}");
Trace.WriteLine($"[EmployeesPage] ❌ StackTrace: {ex.StackTrace}");
// Показываем ошибку напрямую
Task.Run(async () =>
{
await Task.Delay(100);
Page? mainPage = Application.Current?.Windows[0]?.Page;
if (mainPage != null)
{
await mainPage.DisplayAlert("Ошибка EmployeesPage",
$"Ошибка инициализации:\n{ex.Message}\n\nStackTrace:\n{ex.StackTrace}", "OK");
}
});
throw;
}
}
private async Task LoadEmployeesAsync()
{
try
{
Trace.WriteLine("[EmployeesPage] >>> LoadEmployeesAsync START");
LoadingIndicator.IsVisible = true;
LoadingIndicator.IsRunning = true;
Trace.WriteLine("[EmployeesPage] >>> Вызов GetAllEmployeesAsync");
_allEmployees = await ServiceProvider.ApiService.GetAllEmployeesAsync();
Trace.WriteLine($"[EmployeesPage] >>> Получено сотрудников: {_allEmployees.Count}");
_employees.Clear();
foreach (User user in _allEmployees.OrderBy(u => u.FullName))
{
_employees.Add(user);
}
Trace.WriteLine($"[EmployeesPage] ✅ Сотрудники загружены успешно");
// Предзагружаем аватары в фоне
_ = PreloadAvatarsAsync();
}
catch (Exception ex)
{
Trace.WriteLine($"[EmployeesPage] ❌ Ошибка загрузки: {ex.GetType().Name}");
Trace.WriteLine($"[EmployeesPage] Message: {ex.Message}");
Trace.WriteLine($"[EmployeesPage] StackTrace: {ex.StackTrace}");
await DisplayAlert("Ошибка", $"Не удалось загрузить список сотрудников:\n{ex.Message}", "OK");
}
finally
{
LoadingIndicator.IsVisible = false;
LoadingIndicator.IsRunning = false;
RefreshView.IsRefreshing = false;
}
}
private async void OnRefreshing(object sender, EventArgs e)
{
await LoadEmployeesAsync();
}
/// <summary>
/// Попытаться извлечь User из события нажатия (поддерживает CommandParameter, TapGestureRecognizer и BindingContext)
/// </summary>
private static User? GetUserFromTap(object? sender, TappedEventArgs? e)
{
// Сначала пробуем Parameter из TappedEventArgs
if (e?.Parameter is User userFromParam)
return userFromParam;
// Если sender - это TapGestureRecognizer
if (sender is TapGestureRecognizer tr)
{
if (tr.BindingContext is User userFromTr) return userFromTr;
if (tr.Parent is BindableObject parent && parent.BindingContext is User userFromParent) return userFromParent;
}
// Если sender - это элемент с BindingContext (например Border)
if (sender is BindableObject bo && bo.BindingContext is User userFromBo)
{
return userFromBo;
}
return null;
}
/// <summary>
/// Обработчик клика по карточке сотрудника (открытие профиля)
/// </summary>
private async void OnEmployeeCardTapped(object sender, TappedEventArgs e)
{
var selectedEmployee = GetUserFromTap(sender, e);
if (selectedEmployee == null)
{
Trace.WriteLine("[EmployeesPage] ⚠️ Не удалось определить выбранного сотрудника в OnEmployeeCardTapped");
return;
}
Trace.WriteLine($"[EmployeesPage] >>> Открытие профиля: {selectedEmployee.FullName}");
try
{
await Shell.Current.Navigation.PushAsync(new EmployeeProfilePage(selectedEmployee));
}
catch (Exception ex)
{
Trace.WriteLine($"[EmployeesPage] ❌ Ошибка перехода к профилю: {ex.Message}");
await DisplayAlert("Ошибка", "Не удалось открыть профиль сотрудника", "OK");
}
}
/// <summary>
/// Обработчик клика по иконке чата (открытие чата)
/// </summary>
private async void OnChatIconTapped(object sender, TappedEventArgs e)
{
var selectedEmployee = GetUserFromTap(sender, e);
if (selectedEmployee == null)
{
Trace.WriteLine("[EmployeesPage] ⚠️ Не удалось определить выбранного сотрудника в OnChatIconTapped");
return;
}
Trace.WriteLine($"[EmployeesPage] >>> Открытие чата с: {selectedEmployee.FullName}");
try
{
await Shell.Current.Navigation.PushAsync(new ChatPage(selectedEmployee));
}
catch (Exception ex)
{
Trace.WriteLine($"[EmployeesPage] ❌ Ошибка перехода к чату: {ex.Message}");
await DisplayAlert("Ошибка", "Не удалось открыть чат", "OK");
}
}
private void OnSearchTextChanged(object sender, TextChangedEventArgs e)
{
string searchText = e.NewTextValue?.ToLower() ?? string.Empty;
if (string.IsNullOrWhiteSpace(searchText))
{
// Показываем всех сотрудников
_employees.Clear();
foreach (User user in _allEmployees.OrderBy(u => u.FullName))
{
_employees.Add(user);
}
}
else
{
// Фильтруем сотрудников
List<User> filtered = _allEmployees.Where(u =>
u.FullName.ToLower().Contains(searchText) ||
u.Username.ToLower().Contains(searchText) ||
u.DepartmentName.ToLower().Contains(searchText) ||
u.PositionName.ToLower().Contains(searchText)
).ToList();
_employees.Clear();
foreach (User user in filtered.OrderBy(u => u.FullName))
{
_employees.Add(user);
}
}
}
private void OnUserStatusChanged(object? sender, User updatedUser)
{
// Обновляем статус пользователя в списке
MainThread.BeginInvokeOnMainThread(() =>
{
User? user = _employees.FirstOrDefault(u => u.Id == updatedUser.Id);
if (user != null)
{
user.IsOnline = updatedUser.IsOnline;
}
// Обновляем в основном списке
User? allUser = _allEmployees?.FirstOrDefault(u => u.Id == updatedUser.Id);
if (allUser != null)
{
allUser.IsOnline = updatedUser.IsOnline;
}
});
}
protected override void OnDisappearing()
{
base.OnDisappearing();
ServiceProvider.WebSocketService.UserStatusChanged -= OnUserStatusChanged;
}
private async Task PreloadAvatarsAsync()
{
try
{
Trace.WriteLine("[EmployeesPage] >>> Начинаем предзагрузку ават<D0B0><D182>ров...");
await ServiceProvider.ApiService.PreloadUserAvatarsAsync(_allEmployees);
Trace.WriteLine("[EmployeesPage] ✅ Аватары предзагружены");
}
catch (Exception ex)
{
Trace.WriteLine($"[EmployeesPage] ⚠️ Ошибка предзагрузки аватаров: {ex.Message}");
}
}
/// <summary>
/// SelectionChanged handler: откроет профиль выбранного сотрудника (вызывается при SelectionMode=Single)
/// </summary>
private async void EmployeesCollectionView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
try
{
var selected = e.CurrentSelection?.FirstOrDefault() as User;
if (selected == null)
return;
Trace.WriteLine($"[EmployeesPage] >>> SelectionChanged -> открываем профиль: {selected.FullName}");
await Shell.Current.Navigation.PushAsync(new EmployeeProfilePage(selected));
}
catch (Exception ex)
{
Trace.WriteLine($"[EmployeesPage] ❌ Ошибка в SelectionChanged: {ex.Message}");
await DisplayAlert("Ошибка", "Не удалось открыть профиль сотрудника", "OK");
}
finally
{
// Снять выбор, чтобы пользователь мог снова выбрать тот же элемент
if (sender is CollectionView cv)
{
cv.SelectedItem = null;
}
}
}
}