591 lines
18 KiB
Markdown
591 lines
18 KiB
Markdown
# Корпоративное MAUI приложение
|
||
|
||
Кроссплатформенное корпоративное приложение для общения между сотрудниками компании, построенное на .NET MAUI.
|
||
|
||
## 📱 Возможности
|
||
|
||
- ✅ **Аутентификация** - безопасный вход в систему
|
||
- ✅ **Список сотрудников** - просмотр всех пользователей с фильтрацией и поиском
|
||
- ✅ **Личные сообщения** - обмен сообщениями между сотрудниками в реальном времени
|
||
- ✅ **WebSocket подключение** - мгновенная доставка сообщений
|
||
- ✅ **Статусы пользователей** - отображение онлайн/оффлайн статуса
|
||
- ✅ **Индикатор набора текста** - видно, когда собеседник печатает
|
||
- ✅ **Профиль пользователя** - просмотр информации о себе
|
||
- ✅ **Поддержка Android, iOS, Windows, MacCatalyst**
|
||
|
||
## 🏗️ Архитектура
|
||
|
||
### Структура проекта
|
||
|
||
```
|
||
CORP-MAUI/
|
||
├── Models/ # Модели данных
|
||
│ ├── User.cs
|
||
│ ├── Message.cs
|
||
│ └── AuthResponse.cs
|
||
├── Services/ # Бизнес-логика
|
||
│ ├── ApiService.cs # REST API клиент
|
||
│ └── WebSocketService.cs # WebSocket клиент
|
||
├── Pages/ # Страницы приложения
|
||
│ ├── LoginPage.xaml
|
||
│ ├── UsersPage.xaml
|
||
│ ├── ChatPage.xaml
|
||
│ └── ProfilePage.xaml
|
||
├── ServiceProvider.cs # Singleton для сервисов
|
||
├── App.xaml.cs # Точка входа
|
||
└── AppShell.xaml # Навигация
|
||
```
|
||
|
||
### Компоненты
|
||
|
||
#### 1. **ApiService** - REST API клиент
|
||
Отвечает за HTTP запросы к серверу:
|
||
- Аутентификация (`POST /auth/login`)
|
||
- Получение списка пользователей (`GET /users`)
|
||
- Получение сообщений (`GET /messages`)
|
||
- Отправка сообщений (`POST /messages`)
|
||
- Поиск пользователей (`GET /users/search`)
|
||
- Обновление статуса (`PUT /users/status`)
|
||
|
||
#### 2. **WebSocketService** - WebSocket клиент
|
||
Обеспечивает real-time коммуникацию:
|
||
- Подключение к WebSocket серверу
|
||
- Отправка/получение сообщений
|
||
- Индикаторы набора текста
|
||
- Обновление статусов пользователей
|
||
- Автоматическое переподключение
|
||
|
||
#### 3. **ServiceProvider** - Singleton провайдер
|
||
Централизованное управление сервисами приложения.
|
||
|
||
## 🔌 API Endpoints
|
||
|
||
Базовый URL: `https://corp.robotail.pro/api/v1/`
|
||
|
||
### REST API
|
||
|
||
```http
|
||
# Аутентификация
|
||
POST /auth/login
|
||
Content-Type: application/json
|
||
{
|
||
"username": "user",
|
||
"password": "pass"
|
||
}
|
||
|
||
# Получить список пользователей
|
||
GET /users
|
||
Authorization: Bearer {token}
|
||
|
||
# Получить текущего пользователя
|
||
GET /users/me
|
||
Authorization: Bearer {token}
|
||
|
||
# Поиск пользователей
|
||
GET /users/search?q={query}
|
||
Authorization: Bearer {token}
|
||
|
||
# Получить сообщения
|
||
GET /messages?userId={id}
|
||
Authorization: Bearer {token}
|
||
|
||
# Отправить сообщение
|
||
POST /messages
|
||
Authorization: Bearer {token}
|
||
Content-Type: application/json
|
||
{
|
||
"receiverId": 123,
|
||
"content": "Текст сообщения"
|
||
}
|
||
|
||
# Обновить статус
|
||
PUT /users/status
|
||
Authorization: Bearer {token}
|
||
Content-Type: application/json
|
||
{
|
||
"isOnline": true
|
||
}
|
||
```
|
||
|
||
### WebSocket
|
||
|
||
```
|
||
URL: wss://corp.robotail.pro/api/v1/ws
|
||
Headers: Authorization: Bearer {token}
|
||
|
||
# Отправка сообщения
|
||
{
|
||
"type": "message",
|
||
"data": {
|
||
"receiverId": 123,
|
||
"content": "Текст сообщения"
|
||
}
|
||
}
|
||
|
||
# Индикатор набора текста
|
||
{
|
||
"type": "typing",
|
||
"data": {
|
||
"recipientId": 123,
|
||
"isTyping": true
|
||
}
|
||
}
|
||
|
||
# Получение сообщения (от сервера)
|
||
{
|
||
"type": "message",
|
||
"data": {
|
||
"id": 456,
|
||
"senderId": 789,
|
||
"senderName": "Иван Иванов",
|
||
"content": "Привет!",
|
||
"timestamp": "2026-01-08T10:30:00Z"
|
||
}
|
||
}
|
||
|
||
# Обновление статуса пользователя (от сервера)
|
||
{
|
||
"type": "user_status",
|
||
"data": {
|
||
"id": 123,
|
||
"isOnline": true
|
||
}
|
||
}
|
||
```
|
||
|
||
## 🚀 Установка и запуск
|
||
|
||
### Требования
|
||
|
||
- .NET 9.0 SDK
|
||
- Visual Studio 2022 / JetBrains Rider
|
||
- Для Android: Android SDK (см. [ANDROID_SETUP.md](ANDROID_SETUP.md))
|
||
- Для iOS: Xcode и Mac
|
||
|
||
### ⚙️ Настройка Android SDK
|
||
|
||
Если Android SDK установлен по нестандартному пути, создан файл `Directory.Build.props` в корне решения:
|
||
|
||
```xml
|
||
<Project>
|
||
<PropertyGroup>
|
||
<AndroidSdkDirectory>D:\Applications\Android\SDK</AndroidSdkDirectory>
|
||
</PropertyGroup>
|
||
</Project>
|
||
```
|
||
|
||
**Важно:** Измените путь на ваш, если SDK установлен в другом месте.
|
||
|
||
Подробная инструкция: [ANDROID_SETUP.md](ANDROID_SETUP.md)
|
||
|
||
### Скрипты сборки для Android
|
||
|
||
Для удобной сборки Android используйте готовые скрипты:
|
||
|
||
```powershell
|
||
# PowerShell (рекомендуется)
|
||
.\build-android.ps1
|
||
|
||
# Batch
|
||
.\build-android.bat
|
||
```
|
||
|
||
Скрипты автоматически настроят переменные окружения и соберут проект.
|
||
|
||
### Установка зависимостей
|
||
|
||
```powershell
|
||
# CORP-MAUI - Корпоративное приложение для сотрудников
|
||
|
||
Мобильное приложение для внутрикорпоративного общения между сотрудниками компании.
|
||
|
||
## 🚀 Технологии
|
||
|
||
- **.NET MAUI 9.0** - Кросс-платформенный фреймворк
|
||
- **C# 12** - Язык программирования
|
||
- **WebSocket** - Обмен сообщениями в реальном времени
|
||
- **REST API** - Взаимодействие с сервером
|
||
- **JWT Authentication** - Безопасная аутентификация
|
||
- **SecureStorage** - Безопасное хранение токенов
|
||
|
||
## 📱 Возможности
|
||
|
||
### Аутентификация
|
||
- Вход по email и паролю
|
||
- Автоматическое сохранение JWT токенов
|
||
- Автоматическое обновление access токена при истечении
|
||
- Безопасное хранение токенов в SecureStorage
|
||
|
||
### Профиль пользователя
|
||
- Просмотр личной информации
|
||
- Отображение статуса (в сети/не в сети)
|
||
- Выход из системы
|
||
|
||
### Список сотрудников
|
||
- Просмотр всех сотрудников компании
|
||
- Поиск по имени, отделу, должности
|
||
- Отображение статуса онлайн/офлайн
|
||
- Pull-to-refresh для обновления списка
|
||
|
||
### Чат
|
||
- Обмен личными сообщениями
|
||
- Обмен в реальном времени через WebSocket
|
||
- Отображение истории сообщений
|
||
- Индикатор набора текста
|
||
- Резервная отправка через REST API
|
||
|
||
## 🏗️ Архитектура
|
||
|
||
```
|
||
CORP-MAUI/
|
||
├── Models/ # Модели данных
|
||
│ ├── User.cs # Модель пользователя
|
||
│ ├── Message.cs # Модель сообщения
|
||
│ └── AuthResponse.cs # Ответ аутентификации
|
||
├── Services/ # Сервисы
|
||
│ ├── ApiService.cs # HTTP-клиент для REST API
|
||
│ └── WebSocketService.cs # WebSocket-клиент
|
||
├── Pages/ # Страницы приложения
|
||
│ ├── LoginPage.xaml # Страница входа
|
||
│ ├── ProfilePage.xaml # Профиль пользователя
|
||
│ ├── UsersPage.xaml # Список сотрудников
|
||
│ └── ChatPage.xaml # Чат с сотрудником
|
||
└── ServiceProvider.cs # Глобальный провайдер сервисов
|
||
```
|
||
|
||
## 🔌 API Endpoints
|
||
|
||
**Базовый URL:** `https://corp.robotail.pro`
|
||
|
||
### Аутентификация
|
||
```http
|
||
POST /api/auth/token/
|
||
Body: { "email": "user@example.com", "password": "password" }
|
||
Response: { "access": "token", "refresh": "token" }
|
||
|
||
POST /api/auth/token/refresh/
|
||
Body: { "refresh": "token" }
|
||
Response: { "access": "new_token" }
|
||
```
|
||
|
||
### Пользователи
|
||
```http
|
||
GET /api/v1/employees/
|
||
Response: [{ "id": 1, "username": "user", ... }]
|
||
|
||
GET /api/v1/employees/me/
|
||
Response: { "id": 1, "username": "user", ... }
|
||
|
||
GET /api/v1/users/search/?q=query
|
||
Response: [{ "id": 1, "username": "user", ... }]
|
||
|
||
PUT /api/v1/users/status/
|
||
Body: { "isOnline": true }
|
||
```
|
||
|
||
### Сообщения
|
||
```http
|
||
GET /api/v1/messages/
|
||
Response: [{ "id": 1, "content": "Hello", ... }]
|
||
|
||
GET /api/v1/messages/?user_id=1
|
||
Response: [{ "id": 1, "content": "Hello", ... }]
|
||
|
||
POST /api/v1/messages/
|
||
Body: { "senderId": 1, "receiverId": 2, "content": "Hello" }
|
||
```
|
||
|
||
### WebSocket
|
||
```
|
||
Поддерживаются следующие варианты URL (автоматический подбор):
|
||
- wss://corp.robotail.pro/ws (основной)
|
||
- ws://corp.robotail.pro/ws (без SSL)
|
||
- wss://corp.robotail.pro/ws/ (со слешем)
|
||
- и другие варианты...
|
||
|
||
ВАЖНО! Обязательный заголовок при подключении:
|
||
Authorization: Bearer {access_token}
|
||
|
||
Пример подключения:
|
||
var ws = new ClientWebSocket();
|
||
ws.Options.SetRequestHeader("Authorization", $"Bearer {token}");
|
||
await ws.ConnectAsync(new Uri("wss://corp.robotail.pro/ws"), cancellationToken);
|
||
|
||
Типы сообщений:
|
||
- message: Новое сообщение
|
||
- user_status: Изменение статуса пользователя
|
||
- typing: Индикатор набора текста
|
||
|
||
Формат сообщений:
|
||
{
|
||
"type": "message",
|
||
"data": {
|
||
"senderId": 1,
|
||
"receiverId": 2,
|
||
"content": "Текст сообщения",
|
||
"timestamp": "2026-01-09T12:00:00Z"
|
||
}
|
||
}
|
||
```
|
||
|
||
**Примечание**:
|
||
- WebSocketService автоматически пробует разные варианты URL и подключается к первому работающему
|
||
- Заголовок Authorization устанавливается автоматически при вызове `ConnectAsync(token)`
|
||
- Токен передается в формате JWT Bearer token
|
||
|
||
## 🔐 Система управления токенами
|
||
|
||
ApiService автоматически управляет JWT токенами:
|
||
|
||
1. **При входе:**
|
||
- Получает access и refresh токены
|
||
- Сохраняет их в SecureStorage
|
||
- Устанавливает в HTTP заголовки
|
||
|
||
2. **При запросах:**
|
||
- Автоматически добавляет Bearer токен
|
||
- При 401/403 пытается обновить токен
|
||
- Повторяет запрос после обновления
|
||
|
||
3. **При выходе:**
|
||
- Очищает токены из SecureStorage
|
||
- Удаляет заголовки авторизации
|
||
|
||
## 📝 Использование
|
||
|
||
### Пример авторизации
|
||
```csharp
|
||
var result = await ServiceProvider.ApiService.LoginAsync(email, password);
|
||
if (result.Success)
|
||
{
|
||
// Токены автоматически сохранены
|
||
var user = result.User;
|
||
await ServiceProvider.WebSocketService.ConnectAsync(result.Token);
|
||
Application.Current.MainPage = new AppShell();
|
||
}
|
||
```
|
||
|
||
### Пример получения данных
|
||
```csharp
|
||
// Автоматически обновит токен при необходимости
|
||
var employees = await ServiceProvider.ApiService.GetEmployeesAsync();
|
||
var currentUser = await ServiceProvider.ApiService.GetCurrentUserAsync();
|
||
```
|
||
|
||
### Пример отправки сообщения
|
||
```csharp
|
||
var message = new Message
|
||
{
|
||
SenderId = currentUser.Id,
|
||
ReceiverId = recipient.Id,
|
||
Content = "Hello!",
|
||
Timestamp = DateTime.Now,
|
||
Type = MessageType.Personal
|
||
};
|
||
|
||
// Через WebSocket (приоритет)
|
||
if (ServiceProvider.WebSocketService.IsConnected)
|
||
{
|
||
await ServiceProvider.WebSocketService.SendMessageAsync(message);
|
||
}
|
||
else
|
||
{
|
||
// Резервный метод через REST API
|
||
await ServiceProvider.ApiService.SendMessageAsync(message);
|
||
}
|
||
```
|
||
|
||
### Пример выхода
|
||
```csharp
|
||
await ServiceProvider.ApiService.UpdateStatusAsync(false);
|
||
await ServiceProvider.WebSocketService.DisconnectAsync();
|
||
ServiceProvider.ApiService.Logout(); // Очищает токены
|
||
Application.Current.MainPage = new NavigationPage(new LoginPage());
|
||
```
|
||
|
||
## 🔧 Конфигурация
|
||
|
||
Вы можете настроить ApiService при создании:
|
||
|
||
```csharp
|
||
var config = new ApiConfig
|
||
{
|
||
BaseUrl = "https://your-api.com/api",
|
||
TokenObtainPath = "/auth/token/",
|
||
TokenRefreshPath = "/auth/token/refresh/",
|
||
Timeout = 30,
|
||
DefaultHeaders = new Dictionary<string, string>
|
||
{
|
||
{ "Accept", "application/json" },
|
||
{ "X-Custom-Header", "value" }
|
||
}
|
||
};
|
||
|
||
var apiService = new ApiService(config);
|
||
```
|
||
|
||
## 🛠️ Сборка и запуск
|
||
|
||
### Требования
|
||
- Visual Studio 2022 или JetBrains Rider
|
||
- .NET 9.0 SDK
|
||
- Android SDK (для Android)
|
||
- Xcode (для iOS/macOS)
|
||
|
||
### Запуск
|
||
```powershell
|
||
# Android
|
||
dotnet build -t:Run -f net9.0-android
|
||
|
||
# iOS
|
||
dotnet build -t:Run -f net9.0-ios
|
||
|
||
# Windows
|
||
dotnet build -t:Run -f net9.0-windows10.0.19041.0
|
||
```
|
||
|
||
## 📚 Документация
|
||
|
||
- [API_REFACTORING.md](API_REFACTORING.md) - Подробное описание рефакторинга ApiService
|
||
- [.NET MAUI Documentation](https://docs.microsoft.com/dotnet/maui/)
|
||
|
||
## ⚠️ Важные замечания
|
||
|
||
1. **SecureStorage** - Токены хранятся в защищенном хранилище платформы
|
||
2. **Автоматический Refresh** - Access токен обновляется прозрачно при 401/403
|
||
3. **WebSocket Reconnect** - При разрыве соединения нужно реализовать переподключение
|
||
4. **Offline Mode** - Можно добавить локальное кэширование сообщений
|
||
|
||
## 🤝 Вклад
|
||
|
||
Проект находится в разработке. Приветствуются pull requests и issue reports.
|
||
|
||
## 📄 Лицензия
|
||
|
||
Корпоративное приложение для внутреннего использования.
|
||
|
||
---
|
||
|
||
**Версия:** 1.0.0
|
||
**Дата обновления:** 2026-01-09
|
||
dotnet restore
|
||
```
|
||
|
||
### Сборка проекта
|
||
|
||
```powershell
|
||
# Для Android
|
||
dotnet build -f net9.0-android
|
||
|
||
# Для Windows
|
||
dotnet build -f net9.0-windows10.0.19041.0
|
||
|
||
# Для iOS
|
||
dotnet build -f net9.0-ios
|
||
|
||
# Для MacCatalyst
|
||
dotnet build -f net9.0-maccatalyst
|
||
```
|
||
|
||
### Запуск приложения
|
||
|
||
```powershell
|
||
# Android
|
||
dotnet run -f net9.0-android
|
||
|
||
# Windows
|
||
dotnet run -f net9.0-windows10.0.19041.0
|
||
```
|
||
|
||
## 🔧 Конфигурация
|
||
|
||
### Изменение API URL
|
||
|
||
В файле `Services/ApiService.cs`:
|
||
```csharp
|
||
private const string BaseUrl = "https://corp.robotail.pro/api/v1/";
|
||
```
|
||
|
||
В файле `Services/WebSocketService.cs`:
|
||
```csharp
|
||
private const string WebSocketUrl = "wss://corp.robotail.pro/api/v1/ws";
|
||
```
|
||
|
||
## 📚 Используемые технологии
|
||
|
||
- **.NET 9.0** - фреймворк
|
||
- **.NET MAUI** - UI фреймворк
|
||
- **Newtonsoft.Json** - JSON сериализация
|
||
- **System.Net.WebSockets** - WebSocket клиент
|
||
- **SecureStorage** - безопасное хранение данных
|
||
|
||
## 🎨 UI/UX особенности
|
||
|
||
- Material Design стиль
|
||
- Адаптивный дизайн для разных экранов
|
||
- Плавные анимации и переходы
|
||
- Индикаторы загрузки
|
||
- Обработка ошибок с user-friendly сообщениями
|
||
- Pull-to-refresh для обновления данных
|
||
|
||
## 🔐 Безопасность
|
||
|
||
- Токены хранятся в SecureStorage
|
||
- HTTPS для REST API
|
||
- WSS (WebSocket Secure) для real-time коммуникации
|
||
- Автоматический выход при истечении токена
|
||
|
||
## 📝 Примеры использования
|
||
|
||
### Отправка сообщения через WebSocket
|
||
|
||
```csharp
|
||
var message = new Message
|
||
{
|
||
SenderId = currentUser.Id,
|
||
ReceiverId = recipient.Id,
|
||
Content = "Привет!",
|
||
Timestamp = DateTime.Now
|
||
};
|
||
|
||
await ServiceProvider.WebSocketService.SendMessageAsync(message);
|
||
```
|
||
|
||
### Поиск пользователей
|
||
|
||
```csharp
|
||
var users = await ServiceProvider.ApiService.SearchUsersAsync("Иван");
|
||
```
|
||
|
||
### Подписка на новые сообщения
|
||
|
||
```csharp
|
||
ServiceProvider.WebSocketService.MessageReceived += (sender, message) =>
|
||
{
|
||
// Обработка нового сообщения
|
||
Console.WriteLine($"Новое сообщение от {message.SenderName}: {message.Content}");
|
||
};
|
||
```
|
||
|
||
## 🐛 Известные проблемы
|
||
|
||
- WebSocket может разрываться при неактивности (реализовано автоматическое переподключение)
|
||
- На iOS требуются дополнительные разрешения для фоновой работы
|
||
|
||
## 🤝 Вклад в проект
|
||
|
||
Пул-реквесты приветствуются! Для крупных изменений, пожалуйста, сначала откройте issue.
|
||
|
||
## 📄 Лицензия
|
||
|
||
[MIT](https://choosealicense.com/licenses/mit/)
|
||
|
||
## 👥 Автор
|
||
|
||
Создано для корпоративного использования в компании.
|
||
|
||
## 📞 Поддержка
|
||
|
||
При возникновении проблем создайте issue в репозитории проекта.
|
||
|