using System.Collections.ObjectModel; using System.Diagnostics; using CORP_MAUI.Models; namespace CORP_MAUI.Pages; public partial class RequestsPage : ContentPage { private readonly ObservableCollection _requests; private List _allRequests = new(); private string _currentFilter = "all"; private string _searchText = string.Empty; public RequestsPage() { try { Trace.WriteLine("=== REQUESTSPAGE CONSTRUCTOR START ==="); Trace.WriteLine("[RequestsPage] >>> Вызов InitializeComponent"); InitializeComponent(); Trace.WriteLine("[RequestsPage] >>> InitializeComponent завершен"); _requests = new ObservableCollection(); RequestsCollectionView.ItemsSource = _requests; Trace.WriteLine("[RequestsPage] >>> Запуск LoadRequestsAsync"); // Загружаем заявления _ = LoadRequestsAsync(); Trace.WriteLine("=== REQUESTSPAGE CONSTRUCTOR END ==="); } catch (Exception ex) { Trace.WriteLine("=== REQUESTSPAGE CONSTRUCTOR ERROR ==="); Trace.WriteLine($"[RequestsPage] ❌ Тип ошибки: {ex.GetType().FullName}"); Trace.WriteLine($"[RequestsPage] ❌ Сообщение: {ex.Message}"); Trace.WriteLine($"[RequestsPage] ❌ StackTrace: {ex.StackTrace}"); // Показываем ошибку напрямую Task.Run(async () => { await Task.Delay(100); if (Application.Current?.Windows.Count > 0) { Page? mainPage = Application.Current.Windows[0].Page; if (mainPage != null) { await mainPage.DisplayAlert("Ошибка RequestsPage", $"Ошибка инициализации:\n{ex.Message}\n\nStackTrace:\n{ex.StackTrace}", "OK"); } } }); throw; } } private async Task LoadRequestsAsync() { try { Trace.WriteLine("[RequestsPage] >>> LoadRequestsAsync START"); LoadingIndicator.IsVisible = true; LoadingIndicator.IsRunning = true; Trace.WriteLine("[RequestsPage] >>> Вызов GetAllRequestsAsync"); _allRequests = await ServiceProvider.ApiService.GetAllRequestsAsync(); Trace.WriteLine($"[RequestsPage] >>> Получено заявлений: {_allRequests.Count}"); ApplyFilters(); Trace.WriteLine($"[RequestsPage] ✅ Заявления загружены успешно"); } catch (Exception ex) { Trace.WriteLine($"[RequestsPage] ❌ Ошибка загрузки: {ex.GetType().Name}"); Trace.WriteLine($"[RequestsPage] Message: {ex.Message}"); Trace.WriteLine($"[RequestsPage] StackTrace: {ex.StackTrace}"); await DisplayAlert("Ошибка", $"Не удалось загрузить список заявлений:\n{ex.Message}", "OK"); } finally { LoadingIndicator.IsVisible = false; LoadingIndicator.IsRunning = false; RefreshView.IsRefreshing = false; } } private void ApplyFilters() { IEnumerable filtered = _allRequests; // Фильтр по статусу filtered = _currentFilter switch { "pending" => filtered.Where(r => r.Status.Equals("pending", StringComparison.OrdinalIgnoreCase) || r.Status.Equals("waiting", StringComparison.OrdinalIgnoreCase)), "approved" => filtered.Where(r => r.Status.Equals("approved", StringComparison.OrdinalIgnoreCase) || r.Status.Equals("accepted", StringComparison.OrdinalIgnoreCase)), "rejected" => filtered.Where(r => r.Status.Equals("rejected", StringComparison.OrdinalIgnoreCase) || r.Status.Equals("declined", StringComparison.OrdinalIgnoreCase) || r.Status.Equals("cancelled", StringComparison.OrdinalIgnoreCase)), _ => filtered }; // Фильтр по поиску if (!string.IsNullOrWhiteSpace(_searchText)) { string search = _searchText.ToLower(); filtered = filtered.Where(r => r.DisplayType.ToLower().Contains(search) || r.DisplayStatus.ToLower().Contains(search) || r.DisplayDescription.ToLower().Contains(search) || r.EmployeeName.ToLower().Contains(search)); } // Сортировка по дате (новые сверху) filtered = filtered.OrderByDescending(r => r.CreatedAt); _requests.Clear(); foreach (var request in filtered) { _requests.Add(request); } Trace.WriteLine($"[RequestsPage] >>> Отображено заявлений: {_requests.Count}"); } private async void OnRefreshing(object sender, EventArgs e) { await LoadRequestsAsync(); } private void OnSearchTextChanged(object sender, TextChangedEventArgs e) { _searchText = e.NewTextValue ?? string.Empty; ApplyFilters(); } private async void OnRequestSelected(object sender, SelectionChangedEventArgs e) { if (e.CurrentSelection.FirstOrDefault() is Request selectedRequest) { // Сбрасываем выбор RequestsCollectionView.SelectedItem = null; // Показываем детали заявления await ShowRequestDetails(selectedRequest); } } private async Task ShowRequestDetails(Request request) { string details = $"Тип: {request.DisplayType}\n" + $"Статус: {request.DisplayStatus}\n" + $"Дата создания: {request.DisplayCreatedAt}\n"; if (!string.IsNullOrEmpty(request.DisplayPeriod)) details += $"Период: {request.DisplayPeriod}\n"; details += $"\nОт кого: {request.EmployeeName}\n"; if (!string.IsNullOrEmpty(request.Comment)) details += $"\nОписание:\n{request.Comment}\n"; // Получатели if (request.Recipients != null && request.Recipients.Count > 0) { details += $"\n📬 Получатели ({request.Recipients.Count}):\n"; foreach (var recipient in request.Recipients) { details += $" • {recipient.FullName}\n"; } } else if (request.RecipientCount > 0) { details += $"\n📬 Получателей: {request.RecipientCount}\n"; } // В копии if (request.CcUsers != null && request.CcUsers.Count > 0) { details += $"\n📋 В копии ({request.CcUsers.Count}):\n"; foreach (var ccUser in request.CcUsers) { details += $" • {ccUser.FullName}\n"; } } else if (request.CcCount > 0) { details += $"\n📋 В копии: {request.CcCount}\n"; } // Решение if (request.Approver != null) details += $"\n✍️ Решение принял: {request.ApproverName}"; if (request.DecidedAt.HasValue) details += $"\n📅 Дата решения: {request.DecidedAt.Value:dd.MM.yyyy HH:mm}"; await DisplayAlert($"{request.TypeIcon} {request.DisplayType}", details, "Закрыть"); } // ================================ // Обработчики фильтров // ================================ private void OnFilterAllTapped(object sender, TappedEventArgs e) { SetActiveFilter("all"); } private void OnFilterPendingTapped(object sender, TappedEventArgs e) { SetActiveFilter("pending"); } private void OnFilterApprovedTapped(object sender, TappedEventArgs e) { SetActiveFilter("approved"); } private void OnFilterRejectedTapped(object sender, TappedEventArgs e) { SetActiveFilter("rejected"); } private void SetActiveFilter(string filter) { _currentFilter = filter; // Обновляем визуальное состояние кнопок UpdateFilterButtonStyles(); // Применяем фильтры ApplyFilters(); } private void UpdateFilterButtonStyles() { // Сбрасываем все кнопки FilterAll.BackgroundColor = Colors.White; FilterAll.Stroke = Color.FromArgb("#D1D5DB"); if (FilterAll.Content is Label labelAll) labelAll.TextColor = Color.FromArgb("#374151"); FilterPending.BackgroundColor = Colors.White; FilterPending.Stroke = Color.FromArgb("#D1D5DB"); if (FilterPending.Content is Label labelPending) labelPending.TextColor = Color.FromArgb("#374151"); FilterApproved.BackgroundColor = Colors.White; FilterApproved.Stroke = Color.FromArgb("#D1D5DB"); if (FilterApproved.Content is Label labelApproved) labelApproved.TextColor = Color.FromArgb("#374151"); FilterRejected.BackgroundColor = Colors.White; FilterRejected.Stroke = Color.FromArgb("#D1D5DB"); if (FilterRejected.Content is Label labelRejected) labelRejected.TextColor = Color.FromArgb("#374151"); // Активируем выбранную кнопку Border activeButton = _currentFilter switch { "pending" => FilterPending, "approved" => FilterApproved, "rejected" => FilterRejected, _ => FilterAll }; activeButton.BackgroundColor = (Color)Application.Current!.Resources["Primary"]; activeButton.Stroke = Colors.Transparent; if (activeButton.Content is Label activeLabel) activeLabel.TextColor = Colors.White; } }