diff --git a/CORP-MAUI.sln.DotSettings.user b/CORP-MAUI.sln.DotSettings.user
index 6b0b69d..d5a1ca2 100644
--- a/CORP-MAUI.sln.DotSettings.user
+++ b/CORP-MAUI.sln.DotSettings.user
@@ -1,6 +1,11 @@
ForceIncluded
ForceIncluded
+ ForceIncluded
+ ForceIncluded
ForceIncluded
ForceIncluded
- ForceIncluded
\ No newline at end of file
+ ForceIncluded
+ ForceIncluded
+ ForceIncluded
+ ForceIncluded
\ No newline at end of file
diff --git a/CORP-MAUI/App.xaml.cs b/CORP-MAUI/App.xaml.cs
index 3863a29..5810e98 100644
--- a/CORP-MAUI/App.xaml.cs
+++ b/CORP-MAUI/App.xaml.cs
@@ -1,4 +1,6 @@
using CORP_MAUI.Pages;
+using CORP_MAUI.Models;
+using System.Diagnostics;
namespace CORP_MAUI;
@@ -6,23 +8,161 @@ public partial class App : Application
{
public App()
{
+ Trace.WriteLine("╔═════════════════════════════════════════════════════════════════════════════════╗");
+ Trace.WriteLine("║ [App] APPLICATION CONSTRUCTOR STARTED ║");
+ Trace.WriteLine("╚═════════════════════════════════════════════════════════════════════════════════╝");
+
+#if DEBUG
+ Trace.WriteLine("[App] ✅ DEBUG MODE IS ACTIVE!");
+#else
+ Trace.WriteLine("[App] ⚠️ DEBUG MODE IS NOT ACTIVE!");
+#endif
+
InitializeComponent();
+
+ Trace.WriteLine("[App] ✅ Application initialized");
}
protected override Window CreateWindow(IActivationState? activationState)
{
- // Проверяем, есть ли сохраненный токен
- var hasToken = SecureStorage.Default.GetAsync("auth_token").Result != null;
-
- if (hasToken)
+ Trace.WriteLine("[App] >>> CreateWindow called");
+
+ // Создаем окно с начальной страницей загрузки
+#if ANDROID || IOS || MACCATALYST || WINDOWS
+ var loadingPage = new ContentPage
+ {
+ Content = new VerticalStackLayout
+ {
+ VerticalOptions = LayoutOptions.Center,
+ HorizontalOptions = LayoutOptions.Center,
+ Spacing = 20,
+ Children =
+ {
+ new ActivityIndicator
+ {
+ IsRunning = true,
+ Color = Colors.Blue
+ },
+ new Label
+ {
+ Text = "Загрузка...",
+ HorizontalOptions = LayoutOptions.Center
+ }
+ }
+ }
+ };
+
+ var window = new Window(loadingPage);
+#else
+ // Фолбэк для платформ вне целевых (не должен использоваться в текущих TFM)
+ var window = new Window();
+#endif
+
+ // Асинхронно проверяем токен и определяем начальную страницу
+ _ = InitializeAppAsync(window);
+
+ return window;
+ }
+
+ private async Task InitializeAppAsync(Window window)
+ {
+ try
{
- // Пользователь уже вошел в систему
- return new Window(new AppShell());
+ await CheckAuthenticationAndNavigate(window);
}
- else
+ catch (Exception ex)
{
- // Показываем страницу входа
- return new Window(new NavigationPage(new LoginPage()));
+ Trace.WriteLine($"[App] ❌ FATAL: InitializeAppAsync failed: {ex.Message}");
+ Trace.WriteLine($"[App] Exception type: {ex.GetType().Name}");
+ Trace.WriteLine($"[App] Stack trace: {ex.StackTrace}");
+
+ await MainThread.InvokeOnMainThreadAsync(() =>
+ {
+ window.Page = new NavigationPage(new LoginPage());
+ });
}
}
-}
\ No newline at end of file
+
+ private async Task CheckAuthenticationAndNavigate(Window window)
+ {
+ try
+ {
+ Trace.WriteLine("[App] >>> Checking authentication status...");
+
+ // Пытаемся получить данные текущего пользователя
+ // Это автоматически загрузит токены из SecureStorage и проверит их валидность
+ User? user = null;
+
+ try
+ {
+ user = await ServiceProvider.ApiService.GetCurrentUserAsync();
+ }
+ catch (Exception userEx)
+ {
+ Trace.WriteLine($"[App] ⚠️ GetCurrentUserAsync failed: {userEx.Message}");
+ // Если не удалось получить пользователя, значит токен невалиден или отсутствует
+ user = null;
+ }
+
+ if (user != null)
+ {
+ // ✅ Токен валиден, пользователь авторизован
+ Trace.WriteLine($"[App] ✅ User authenticated: {user.Username} (ID: {user.Id})");
+ Trace.WriteLine($"[App] Email: {user.Email}");
+
+ // Подключаемся к WebSocket
+ try
+ {
+ Trace.WriteLine("[App] >>> Connecting to WebSocket...");
+ var token = ServiceProvider.ApiService.GetAccessToken();
+
+ if (!string.IsNullOrEmpty(token))
+ {
+ await ServiceProvider.WebSocketService.ConnectAsync(token);
+ Trace.WriteLine("[App] ✅ WebSocket connected successfully");
+ }
+ else
+ {
+ Trace.WriteLine("[App] ⚠️ No access token available for WebSocket");
+ }
+ }
+ catch (Exception wsEx)
+ {
+ Trace.WriteLine($"[App] ⚠️ WebSocket connection failed: {wsEx.Message}");
+ // Продолжаем работу без WebSocket - это не критично
+ }
+
+ // Переходим сразу на главную страницу (AppShell)
+ Trace.WriteLine("[App] >>> Navigating to AppShell");
+ await MainThread.InvokeOnMainThreadAsync(() =>
+ {
+ window.Page = new AppShell();
+ Trace.WriteLine("[App] ✅ Navigation to AppShell completed");
+ });
+ }
+ else
+ {
+ // ❌ Токен отсутствует или невалиден, показываем страницу входа
+ Trace.WriteLine("[App] ℹ️ No valid authentication found");
+ Trace.WriteLine("[App] >>> Showing LoginPage");
+
+ await MainThread.InvokeOnMainThreadAsync(() =>
+ {
+ window.Page = new NavigationPage(new LoginPage());
+ Trace.WriteLine("[App] ✅ Navigation to LoginPage completed");
+ });
+ }
+ }
+ catch (Exception ex)
+ {
+ Trace.WriteLine($"[App] ❌ Authentication check failed: {ex.Message}");
+ Trace.WriteLine($"[App] Exception type: {ex.GetType().Name}");
+ Trace.WriteLine($"[App] >>> Fallback to LoginPage");
+
+ await MainThread.InvokeOnMainThreadAsync(() =>
+ {
+ window.Page = new NavigationPage(new LoginPage());
+ });
+ }
+ }
+}
diff --git a/CORP-MAUI/AppShell.xaml b/CORP-MAUI/AppShell.xaml
index dbf0ef8..f17cc63 100644
--- a/CORP-MAUI/AppShell.xaml
+++ b/CORP-MAUI/AppShell.xaml
@@ -3,22 +3,18 @@
x:Class="CORP_MAUI.AppShell"
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
- xmlns:pages="clr-namespace:CORP_MAUI.Pages"
- Title="Корпоративный портал"
- FlyoutBackgroundColor="{StaticResource Primary}">
+ xmlns:pages="clr-namespace:CORP_MAUI.Pages">
+
-
+ ContentTemplate="{DataTemplate pages:UsersPage}" />
+ ContentTemplate="{DataTemplate pages:ProfilePage}" />
diff --git a/CORP-MAUI/AppShell.xaml.cs b/CORP-MAUI/AppShell.xaml.cs
index 95b5776..2f5c5c3 100644
--- a/CORP-MAUI/AppShell.xaml.cs
+++ b/CORP-MAUI/AppShell.xaml.cs
@@ -1,4 +1,5 @@
-using CORP_MAUI.Pages;
+using System.Diagnostics;
+using CORP_MAUI.Pages;
namespace CORP_MAUI;
@@ -6,39 +7,103 @@ public partial class AppShell : Shell
{
public AppShell()
{
- InitializeComponent();
+ try
+ {
+ Trace.WriteLine("=== APPSHELL CONSTRUCTOR START ===");
+ Trace.WriteLine("[AppShell] >>> Вызов InitializeComponent");
+
+ InitializeComponent();
+
+ Trace.WriteLine("[AppShell] >>> InitializeComponent завершен");
+ Trace.WriteLine("[AppShell] >>> Регистрация маршрутов");
- // Регистрация маршрутов для навигации
- Routing.RegisterRoute(nameof(ChatPage), typeof(ChatPage));
+ // Регистрация маршрутов для навигации
+ Routing.RegisterRoute(nameof(ChatPage), typeof(ChatPage));
- // Инициализация при загрузке
- _ = InitializeAsync();
+ Trace.WriteLine("[AppShell] ✅ AppShell инициализирован");
+ Trace.WriteLine("=== APPSHELL CONSTRUCTOR END ===");
+
+ // Инициализация без ожидания (так await нельзя из синхронного конструктора)
+ _ = InitializeAsync();
+ }
+ catch (Exception ex)
+ {
+ Trace.WriteLine("=== APPSHELL CONSTRUCTOR ERROR ===");
+ Trace.WriteLine($"[AppShell] ❌ Тип ошибки: {ex.GetType().FullName}");
+ Trace.WriteLine($"[AppShell] ❌ Сообщение: {ex.Message}");
+ Trace.WriteLine($"[AppShell] ❌ StackTrace: {ex.StackTrace}");
+ if (ex.InnerException != null)
+ {
+ Trace.WriteLine($"[AppShell] ❌ InnerException: {ex.InnerException.Message}");
+ Trace.WriteLine($"[AppShell] ❌ InnerException StackTrace: {ex.InnerException.StackTrace}");
+ }
+
+ // Показываем ошибку в диалоге
+ Task.Run(async () =>
+ {
+ await Task.Delay(100);
+ await MainThread.InvokeOnMainThreadAsync(async () =>
+ {
+ var mainPage = Application.Current?.Windows[0]?.Page;
+ if (mainPage != null)
+ {
+ await mainPage.DisplayAlert("Ошибка AppShell",
+ $"Ошибка инициализации AppShell:\n{ex.Message}\n\nStackTrace:\n{ex.StackTrace}", "OK");
+ }
+ });
+ });
+
+ throw;
+ }
}
private async Task InitializeAsync()
{
try
{
- // Инициализируем сервисы
+ Trace.WriteLine("[AppShell] >>> Начало InitializeAsync");
+
+ // Инициализация сервисов (если они не инициализированы)
ServiceProvider.Initialize();
+ Trace.WriteLine($"[AppShell] IsAuthenticated: {ServiceProvider.ApiService.IsAuthenticated}");
+
// Проверяем, авторизован ли пользователь (токены загружаются автоматически в ApiService)
if (ServiceProvider.ApiService.IsAuthenticated)
{
// Получаем токен для WebSocket
var accessToken = await SecureStorage.GetAsync("api.jwt_access");
- if (!string.IsNullOrEmpty(accessToken))
+ Trace.WriteLine($"[AppShell] Access token exists: {!string.IsNullOrEmpty(accessToken)}");
+ Trace.WriteLine($"[AppShell] WebSocket connected: {ServiceProvider.WebSocketService.IsConnected}");
+
+ if (!string.IsNullOrEmpty(accessToken) && !ServiceProvider.WebSocketService.IsConnected)
{
- // Подключаем WebSocket
+ Trace.WriteLine("[AppShell] >>> Подключение WebSocket из AppShell");
+ // Подключаем WebSocket только если его еще не подключен
await ServiceProvider.WebSocketService.ConnectAsync(accessToken);
+ Trace.WriteLine("[AppShell] ✅ WebSocket подключен из AppShell");
+ }
+ else if (ServiceProvider.WebSocketService.IsConnected)
+ {
+ Trace.WriteLine("[AppShell] WebSocket уже подключен, пропускаем");
}
}
+ else
+ {
+ Trace.WriteLine("[AppShell] ⚠️ Пользователь не авторизован");
+ }
+
+ Trace.WriteLine("[AppShell] ✅ InitializeAsync завершен");
}
catch (Exception ex)
{
+ Trace.WriteLine($"[AppShell] ❌ Ошибка InitializeAsync: {ex.Message}");
+ Trace.WriteLine($"[AppShell] StackTrace: {ex.StackTrace}");
+
await DisplayAlert("Ошибка", $"Ошибка инициализации: {ex.Message}", "OK");
}
}
}
+
diff --git a/CORP-MAUI/CORP-MAUI.csproj b/CORP-MAUI/CORP-MAUI.csproj
index 24c5197..bf7e5ea 100644
--- a/CORP-MAUI/CORP-MAUI.csproj
+++ b/CORP-MAUI/CORP-MAUI.csproj
@@ -39,8 +39,13 @@
10.0.17763.0
10.0.17763.0
6.5
- Debug;Release;Android
- AnyCPU
+
+
+ D:\Applications\Java\JDK\Temurin\jdk-21.0.9+10
+
+
+ DEBUG;TRACE
+ TRACE
diff --git a/CORP-MAUI/DebugCheck.cs b/CORP-MAUI/DebugCheck.cs
index e69de29..e01ed7a 100644
--- a/CORP-MAUI/DebugCheck.cs
+++ b/CORP-MAUI/DebugCheck.cs
@@ -0,0 +1,20 @@
+using System.Diagnostics;
+
+namespace CORP_MAUI;
+
+public static class DebugCheck
+{
+ public static void PrintDebugStatus()
+ {
+#if DEBUG
+ Trace.WriteLine("╔══════════════════════════════════════════════════════════════════════════════════╗");
+ Trace.WriteLine("║ ✅ DEBUG СИМВОЛ ОПРЕДЕЛЕН! Режим отладки АКТИВЕН! ║");
+ Trace.WriteLine("╚═════════════════════════════════════════════════════════════════════════════════╝");
+#else
+ Trace.WriteLine("╔═════════════════════════════════════════════════════════════════════════════════╗");
+ Trace.WriteLine("║ ❌ DEBUG СИМВОЛ НЕ ОПРЕДЕЛЕН! Режим отладки НЕ АКТИВЕН! ║");
+ Trace.WriteLine("╚══════════════════════════════════════════════════════════════════════════════════╝");
+#endif
+ }
+}
+
diff --git a/CORP-MAUI/DebugChecker.cs b/CORP-MAUI/DebugChecker.cs
deleted file mode 100644
index e69de29..0000000
diff --git a/CORP-MAUI/DebugTest.cs b/CORP-MAUI/DebugTest.cs
deleted file mode 100644
index 1bcbf26..0000000
--- a/CORP-MAUI/DebugTest.cs
+++ /dev/null
@@ -1,25 +0,0 @@
-using System.Diagnostics;
-
-namespace CORP_MAUI;
-
-public static class DebugTest
-{
- static DebugTest()
- {
-#if DEBUG
- Trace.WriteLine("╔══════════════════════════════════════════════════════════════════════════════════╗");
- Trace.WriteLine("║ ✅ DEBUG IS DEFINED ✅ ║");
- Trace.WriteLine("╚══════════════════════════════════════════════════════════════════════════════════╝");
-#else
- Trace.WriteLine("╔══════════════════════════════════════════════════════════════════════════════════╗");
- Trace.WriteLine("║ ❌ DEBUG IS NOT DEFINED ❌ ║");
- Trace.WriteLine("╚══════════════════════════════════════════════════════════════════════════════════╝");
-#endif
- }
-
- public static void Check()
- {
- // Пустой метод для вызова статического конструктора
- }
-}
-
diff --git a/CORP-MAUI/MauiProgram.cs b/CORP-MAUI/MauiProgram.cs
index 4a2218d..312f378 100644
--- a/CORP-MAUI/MauiProgram.cs
+++ b/CORP-MAUI/MauiProgram.cs
@@ -1,4 +1,6 @@
-using Microsoft.Extensions.Logging;
+using System.Diagnostics;
+using CORP_MAUI.Services;
+using CORP_MAUI.Pages;
namespace CORP_MAUI;
@@ -16,9 +18,26 @@ public static class MauiProgram
});
#if DEBUG
- builder.Logging.AddDebug();
+ Trace.Listeners.Clear();
+ Trace.Listeners.Add(new DefaultTraceListener());
+ Trace.AutoFlush = true;
+
+ Trace.WriteLine("╔══════════════════════════════════════════════════════════════════════════════════╗");
+ Trace.WriteLine("║ [MauiProgram] DEBUG MODE ENABLED - TRACE LISTENER CONFIGURED ║");
+ Trace.WriteLine("╚══════════════════════════════════════════════════════════════════════════════════╝");
#endif
+ // Регистрируем сервисы
+ builder.Services.AddSingleton();
+ builder.Services.AddSingleton();
+
+ // Регистрируем страницы
+ builder.Services.AddTransient();
+ builder.Services.AddTransient();
+ builder.Services.AddTransient();
+ builder.Services.AddTransient();
+ builder.Services.AddTransient();
+
return builder.Build();
}
}
\ No newline at end of file
diff --git a/CORP-MAUI/Models/CalendarEvent.cs b/CORP-MAUI/Models/CalendarEvent.cs
index e69de29..48b1bd5 100644
--- a/CORP-MAUI/Models/CalendarEvent.cs
+++ b/CORP-MAUI/Models/CalendarEvent.cs
@@ -0,0 +1,17 @@
+namespace CORP_MAUI.Models;
+
+///
+/// Модель события календаря
+///
+public class CalendarEvent
+{
+ public int Id { get; set; }
+ public string Title { get; set; } = string.Empty;
+ public string Description { get; set; } = string.Empty;
+ public DateTime StartDate { get; set; }
+ public DateTime EndDate { get; set; }
+ public string Location { get; set; } = string.Empty;
+ public List Participants { get; set; } = new();
+ public User? Creator { get; set; }
+}
+
diff --git a/CORP-MAUI/Models/Comment.cs b/CORP-MAUI/Models/Comment.cs
index e69de29..fcbefbe 100644
--- a/CORP-MAUI/Models/Comment.cs
+++ b/CORP-MAUI/Models/Comment.cs
@@ -0,0 +1,63 @@
+
+using System.Text.Json.Serialization;
+
+namespace CORP_MAUI.Models;
+
+///
+/// Модель комментария
+///
+public class Comment
+{
+ public int Id { get; set; }
+
+ [JsonPropertyName("content")]
+ public string Content { get; set; } = string.Empty;
+
+ [JsonPropertyName("body")]
+ public string? Body { get; set; }
+
+ [JsonPropertyName("text")]
+ public string? Text { get; set; }
+
+ [JsonIgnore]
+ public string DisplayContent
+ {
+ get
+ {
+ if (!string.IsNullOrWhiteSpace(Content)) return Content;
+ if (!string.IsNullOrWhiteSpace(Body)) return Body;
+ return Text ?? string.Empty;
+ }
+ }
+
+ public User? Author { get; set; }
+
+ [JsonPropertyName("post")]
+ public int Post { get; set; }
+
+ [JsonPropertyName("created_at")]
+ public DateTime CreatedAt { get; set; }
+
+ [JsonPropertyName("date")]
+ public DateTime? Date { get; set; }
+
+ [JsonIgnore]
+ public DateTime DisplayDate
+ {
+ get
+ {
+ // Если CreatedAt валидный (больше 2000 года, чтоб отсечь дефолт), берем его
+ if (CreatedAt.Year > 2000) return CreatedAt;
+ // Иначе пробуем поле Date
+ if (Date.HasValue) return Date.Value;
+ // Иначе текущее время
+ return DateTime.Now;
+ }
+ }
+
+ [JsonPropertyName("updated_at")]
+ public DateTime UpdatedAt { get; set; }
+
+ [JsonPropertyName("likes_count")]
+ public int LikesCount { get; set; }
+}
diff --git a/CORP-MAUI/Models/Department.cs b/CORP-MAUI/Models/Department.cs
index e69de29..109ccab 100644
--- a/CORP-MAUI/Models/Department.cs
+++ b/CORP-MAUI/Models/Department.cs
@@ -0,0 +1,14 @@
+namespace CORP_MAUI.Models;
+
+///
+/// Модель отдела
+///
+public class Department
+{
+ public int Id { get; set; }
+ public string Name { get; set; } = string.Empty;
+ public string Description { get; set; } = string.Empty;
+ public int? Parent { get; set; }
+ public int EmployeesCount { get; set; }
+ public User? Head { get; set; }
+}
diff --git a/CORP-MAUI/Models/DepartmentRole.cs b/CORP-MAUI/Models/DepartmentRole.cs
index e69de29..b37fd6c 100644
--- a/CORP-MAUI/Models/DepartmentRole.cs
+++ b/CORP-MAUI/Models/DepartmentRole.cs
@@ -0,0 +1,14 @@
+namespace CORP_MAUI.Models;
+
+///
+/// Модель роли в отделе
+///
+public class DepartmentRole
+{
+ public int Id { get; set; }
+ public string Name { get; set; } = string.Empty;
+ public string Description { get; set; } = string.Empty;
+ public Department? Department { get; set; }
+ public List Permissions { get; set; } = new();
+}
+
diff --git a/CORP-MAUI/Models/Document.cs b/CORP-MAUI/Models/Document.cs
index e69de29..ccbd0e0 100644
--- a/CORP-MAUI/Models/Document.cs
+++ b/CORP-MAUI/Models/Document.cs
@@ -0,0 +1,17 @@
+namespace CORP_MAUI.Models;
+
+///
+/// Модель документа
+///
+public class Document
+{
+ public int Id { get; set; }
+ public string Title { get; set; } = string.Empty;
+ public string Description { get; set; } = string.Empty;
+ public string FileUrl { get; set; } = string.Empty;
+ public DateTime CreatedAt { get; set; }
+ public DateTime UpdatedAt { get; set; }
+ public User? Author { get; set; }
+ public string Category { get; set; } = string.Empty;
+}
+
diff --git a/CORP-MAUI/Models/EmployeeAction.cs b/CORP-MAUI/Models/EmployeeAction.cs
index e69de29..f93618d 100644
--- a/CORP-MAUI/Models/EmployeeAction.cs
+++ b/CORP-MAUI/Models/EmployeeAction.cs
@@ -0,0 +1,18 @@
+namespace CORP_MAUI.Models;
+
+///
+/// Модель действия сотрудника
+///
+public class EmployeeAction
+{
+ public int Id { get; set; }
+ public User? Employee { get; set; }
+ public string Comment { get; set; } = string.Empty;
+ public object? Extra { get; set; }
+ public List