343 lines
18 KiB
C#
343 lines
18 KiB
C#
using Avalonia.Controls.ApplicationLifetimes;
|
||
using domain.Models;
|
||
using domain.UseCase;
|
||
using Presence.Desktop.Views;
|
||
using ReactiveUI;
|
||
using System;
|
||
using System.Collections.Generic;
|
||
using System.Collections.ObjectModel;
|
||
using System.Linq;
|
||
using System.Reactive;
|
||
using System.Reactive.Linq;
|
||
using System.Windows.Input;
|
||
using Avalonia;
|
||
using System.IO;
|
||
using CsvHelper;
|
||
using CsvHelper.Configuration;
|
||
using data.RemoteData;
|
||
|
||
namespace Presence.Desktop.ViewModels
|
||
{
|
||
public class GroupViewModel : ViewModelBase, IRoutableViewModel
|
||
{
|
||
// Объявляем поле для доступа к удаленной базе данных. Используется для доступа к данным о группах и пользователях.
|
||
private readonly RemoteDatabaseContext _remoteDatabaseContext;
|
||
|
||
// URL-сегмент для маршрутизации. Используется ReactiveUI для навигации.
|
||
public string? UrlPathSegment { get; }
|
||
// Экземпляр экрана, используемый для навигации. Предоставляет возможность перехода к другим представлениям.
|
||
public IScreen HostScreen { get; }
|
||
|
||
// Объекты для работы с бизнес-логикой. Обеспечивают взаимодействие с бизнес-слоем приложения.
|
||
private readonly UseCaseGeneratePresence _presenceUseCase; // Для генерации присутствия (возможно, не используется в этом ViewModel)
|
||
private readonly GroupUseCase _groupUseCase; // Для работы с группами (добавление, удаление, обновление)
|
||
|
||
// Временный источник данных для групп. Используется до загрузки данных из базы данных.
|
||
private List<GroupPresenter> groupPresentersDataSource = new List<GroupPresenter>();
|
||
|
||
// Коллекция групп, отображаемых в интерфейсе. Используется ReactiveUI для обновления интерфейса при изменении данных.
|
||
private ObservableCollection<GroupPresenter> _groups;
|
||
public ObservableCollection<GroupPresenter> Groups => _groups;
|
||
|
||
// Выбранная группа в интерфейсе. Изменения этого свойства вызывают обновление списка пользователей.
|
||
private GroupPresenter? _selectedGroupItem;
|
||
public GroupPresenter? SelectedGroupItem
|
||
{
|
||
get => _selectedGroupItem;
|
||
set => this.RaiseAndSetIfChanged(ref _selectedGroupItem, value);
|
||
}
|
||
|
||
// Коллекция пользователей, связанных с выбранной группой. Обновляется при изменении выбранной группы.
|
||
public ObservableCollection<UserPresenter> Users { get => _users; }
|
||
private ObservableCollection<UserPresenter> _users;
|
||
|
||
// Список доступных опций сортировки пользователей.
|
||
public List<string> SortOptions { get; } = new List<string> { "По фамилии", "По убыванию" };
|
||
|
||
// Выбранная опция сортировки пользователей. Изменение этого свойства вызывает сортировку списка пользователей.
|
||
private string _selectedSortOption;
|
||
public string SelectedSortOption
|
||
{
|
||
get => _selectedSortOption;
|
||
set => this.RaiseAndSetIfChanged(ref _selectedSortOption, value);
|
||
}
|
||
|
||
// Свойства, указывающие, доступны ли команды удаления и редактирования. Зависят от количества выбранных пользователей.
|
||
public bool CanDelete => SelectedUsers?.Count > 0;
|
||
public bool CanEdit => SelectedUsers?.Count == 1;
|
||
|
||
// Коллекция выбранных пользователей. Изменения в этой коллекции обновляют состояние команд.
|
||
public ObservableCollection<UserPresenter> SelectedUsers { get; set; } = new ObservableCollection<UserPresenter>();
|
||
|
||
// Реактивные команды для обработки действий пользователя. Обеспечивают реактивное поведение интерфейса.
|
||
public ReactiveCommand<Unit, Unit> OnDeleteUserClicks { get; }
|
||
public ReactiveCommand<Unit, Unit> EditUserCommand { get; }
|
||
public ReactiveCommand<Unit, Unit> NextPageCommand { get; }
|
||
|
||
// Команды для удаления всех студентов и добавления студента.
|
||
public ICommand RemoveAllStudentsCommand { get; }
|
||
public ICommand AddStudentCommand { get; }
|
||
|
||
// Конструктор ViewModel. Инициализирует зависимости и устанавливает начальные значения.
|
||
public GroupViewModel(IScreen screen, GroupUseCase groupUseCase, UseCaseGeneratePresence presenceUseCase, RemoteDatabaseContext remoteDatabaseContext)
|
||
{
|
||
_groupUseCase = groupUseCase;
|
||
_presenceUseCase = presenceUseCase;
|
||
HostScreen = screen;
|
||
_remoteDatabaseContext = remoteDatabaseContext; // Инициализация контекста базы данных
|
||
|
||
// Инициализация реактивных команд с условиями выполнения.
|
||
OnDeleteUserClicks = ReactiveCommand.Create(OnDeleteUserClick, this.WhenAnyValue(vm => vm.CanDelete));
|
||
EditUserCommand = ReactiveCommand.Create(OnEditUserClick, this.WhenAnyValue(vm => vm.CanEdit));
|
||
|
||
RefreshGroups(); // Загрузка и обновление списка групп
|
||
|
||
_groups = new ObservableCollection<GroupPresenter>(groupPresentersDataSource);
|
||
_users = new ObservableCollection<UserPresenter>();
|
||
|
||
// Подписка на изменения выбранной группы для обновления списка пользователей.
|
||
this.WhenAnyValue(vm => vm.SelectedGroupItem)
|
||
.Subscribe(vm => SetUsers());
|
||
|
||
// Подписка на изменения выбранной опции сортировки для сортировки списка пользователей.
|
||
this.WhenAnyValue(vm => vm.SelectedSortOption)
|
||
.Subscribe(_ => SortUsers());
|
||
|
||
// Инициализация команд добавления и удаления студентов.
|
||
RemoveAllStudentsCommand = ReactiveCommand.Create(RemoveAllStudents);
|
||
AddStudentCommand = ReactiveCommand.Create(AddStudent);
|
||
|
||
// Обработчик изменений в коллекции выбранных пользователей для обновления состояния команд.
|
||
SelectedUsers.CollectionChanged += (s, e) =>
|
||
{
|
||
this.RaisePropertyChanged(nameof(CanDelete));
|
||
this.RaisePropertyChanged(nameof(CanEdit));
|
||
};
|
||
|
||
NextPageCommand = ReactiveCommand.Create(NextPageButton);
|
||
}
|
||
|
||
// Установка списка пользователей для выбранной группы. Очищает существующий список и добавляет пользователей из выбранной группы.
|
||
private void SetUsers()
|
||
{
|
||
if (SelectedGroupItem?.users == null) return;
|
||
|
||
Users.Clear(); // Очищаем список пользователей
|
||
foreach (var item in SelectedGroupItem.users)
|
||
{
|
||
Users.Add(item); // Добавляем пользователей из выбранной группы
|
||
}
|
||
|
||
SortUsers(); // Сортируем пользователей
|
||
}
|
||
|
||
// Сортировка списка пользователей по выбранному критерию.
|
||
private void SortUsers()
|
||
{
|
||
if (SelectedGroupItem?.users == null) return;
|
||
|
||
var sortedUsers = SelectedGroupItem.users.ToList(); // Создаем копию списка пользователей
|
||
|
||
switch (SelectedSortOption)
|
||
{
|
||
case "По фамилии":
|
||
sortedUsers = sortedUsers.OrderBy(u => u.Name).ToList(); // Сортировка по имени
|
||
break;
|
||
case "По убыванию":
|
||
sortedUsers = sortedUsers.OrderByDescending(u => u.Name).ToList(); // Сортировка в обратном порядке
|
||
break;
|
||
}
|
||
|
||
Users.Clear(); // Очищаем список пользователей
|
||
foreach (var item in sortedUsers)
|
||
{
|
||
Users.Add(item); // Добавляем отсортированных пользователей
|
||
}
|
||
}
|
||
|
||
// Удаление всех студентов из выбранной группы.
|
||
private void RemoveAllStudents()
|
||
{
|
||
if (SelectedGroupItem == null) return;
|
||
|
||
_groupUseCase.RemoveAllStudentsFromGroup(SelectedGroupItem.Id); // Удаляем студентов из группы через UseCase
|
||
SelectedGroupItem.users = new List<UserPresenter>(); // Обновляем список пользователей в группе
|
||
SetUsers(); // Обновляем список пользователей в ViewModel
|
||
}
|
||
|
||
// Переход на следующую страницу (представление).
|
||
private void NextPageButton()
|
||
{
|
||
// Создаем новые экземпляры репозитория и UseCase для следующего представления.
|
||
var groupRepository = new SQLGroupRepositoryImpl(_remoteDatabaseContext);
|
||
var groupUseCase = new GroupUseCase(groupRepository);
|
||
|
||
// Переход к представлению PresenceViewModel
|
||
HostScreen.Router.Navigate.Execute(new PresenceViewModel(HostScreen, groupUseCase, _presenceUseCase));
|
||
}
|
||
|
||
// Добавление студентов из CSV файла.
|
||
private void AddStudent()
|
||
{
|
||
// Замените на корректный путь к вашему CSV файлу.
|
||
string csvFilePath = @"C:\Users\VivoBook 15X\Desktop\Программные модули\Group.csv";
|
||
|
||
List<UserPresenter> students;
|
||
try
|
||
{
|
||
students = ReadStudentsFromCsv(csvFilePath); // Читаем студентов из CSV файла
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Console.WriteLine($"Ошибка при чтении CSV: {ex.Message}"); // Обработка исключений
|
||
return;
|
||
}
|
||
|
||
if (SelectedGroupItem == null) return;
|
||
|
||
// Добавляем каждого студента в выбранную группу.
|
||
foreach (var student in students)
|
||
{
|
||
_groupUseCase.AddStudentToGroup(SelectedGroupItem.Id, new User { FIO = student.Name }); // Добавляем студента через UseCase
|
||
|
||
var newStudent = new UserPresenter
|
||
{
|
||
Name = student.Name,
|
||
Group = SelectedGroupItem // Устанавливаем ссылку на группу
|
||
};
|
||
|
||
var updatedUsers = SelectedGroupItem.users?.ToList() ?? new List<UserPresenter>();
|
||
updatedUsers.Add(newStudent);
|
||
SelectedGroupItem.users = updatedUsers;
|
||
}
|
||
SetUsers(); // Обновляем список пользователей
|
||
}
|
||
|
||
// Чтение студентов из CSV файла.
|
||
private List<UserPresenter> ReadStudentsFromCsv(string filePath)
|
||
{
|
||
var students = new List<UserPresenter>();
|
||
|
||
try
|
||
{
|
||
using (var reader = new StreamReader(filePath))
|
||
using (var csv = new CsvReader(reader, new CsvConfiguration(System.Globalization.CultureInfo.InvariantCulture)
|
||
{
|
||
HasHeaderRecord = true, // Указываем, что в CSV есть заголовок
|
||
Delimiter = "," // Разделитель в CSV файле
|
||
}))
|
||
{
|
||
var records = csv.GetRecords<StudentCsvModel>().ToList(); // Читаем записи из CSV
|
||
foreach (var record in records)
|
||
{
|
||
var student = new UserPresenter
|
||
{
|
||
Guid = Guid.NewGuid(), // Генерируем уникальный идентификатор
|
||
Name = record.Name // Устанавливаем имя студента
|
||
};
|
||
students.Add(student); // Добавляем студента в список
|
||
}
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Console.WriteLine($"Ошибка при чтении CSV файла: {ex.Message}"); // Обработка исключений
|
||
}
|
||
|
||
return students; // Возвращаем список студентов
|
||
}
|
||
|
||
// Обработка события удаления пользователя.
|
||
public void OnDeleteUserClick()
|
||
{
|
||
if (SelectedUsers.Count == 0 || SelectedGroupItem?.users == null)
|
||
return;
|
||
|
||
foreach (var user in SelectedUsers.ToList())
|
||
{
|
||
_groupUseCase.RemoveUserByGuid(user.Guid); // Удаляем пользователя через UseCase
|
||
|
||
// Обновляем список пользователей в выбранной группе.
|
||
var updatedUsers = SelectedGroupItem.users.Where(u => u.Guid != user.Guid).ToList();
|
||
SelectedGroupItem.users = new List<UserPresenter>(updatedUsers);
|
||
}
|
||
|
||
SetUsers(); // Обновляем список пользователей
|
||
SelectedUsers.Clear(); // Очищаем список выбранных пользователей
|
||
this.RaisePropertyChanged(nameof(CanDelete)); // Обновляем состояние команды удаления
|
||
this.RaisePropertyChanged(nameof(CanEdit)); // Обновляем состояние команды редактирования
|
||
}
|
||
|
||
// Обработка события редактирования пользователя.
|
||
public async void OnEditUserClick()
|
||
{
|
||
var user = SelectedUsers.FirstOrDefault(); // Получаем первого выбранного пользователя
|
||
if (user == null) return;
|
||
|
||
var groups = _groupUseCase.GetAllGroups(); // Получаем все группы
|
||
|
||
// Преобразуем группы из domain.Models.Group в GroupPresenter
|
||
var groupPresenters = groups.Select(g => new GroupPresenter
|
||
{
|
||
Id = g.Id,
|
||
Name = g.Name,
|
||
users = g.Users?.Select(u => new UserPresenter
|
||
{
|
||
Name = u.FIO,
|
||
Guid = u.Guid,
|
||
Group = new GroupPresenter { Id = g.Id, Name = g.Name }
|
||
}).ToList()
|
||
}).ToList();
|
||
|
||
// Создаем диалоговое окно для редактирования пользователя.
|
||
var editDialog = new EditUserDialog(user.Guid, user.Name, user.Group.Id, groupPresenters);
|
||
|
||
var mainWindow = (Application.Current.ApplicationLifetime as IClassicDesktopStyleApplicationLifetime)?.MainWindow;
|
||
if (mainWindow == null) return;
|
||
|
||
// Открываем диалоговое окно и ожидаем результата.
|
||
var result = await editDialog.ShowDialog(mainWindow);
|
||
|
||
if (result != (null, null))
|
||
{
|
||
var newName = result.Item1; // Новое имя пользователя
|
||
var newGroup = result.Item2; // Новая группа пользователя
|
||
|
||
// Обновляем пользователя.
|
||
user.Name = newName;
|
||
user.Group = newGroup;
|
||
|
||
_groupUseCase.UpdateUser(user.Guid, user.Name, user.Group.Id); // Сохраняем изменения через UseCase
|
||
|
||
SetUsers(); // Обновляем список пользователей
|
||
SelectedUsers.Clear(); // Очищаем список выбранных пользователей
|
||
this.RaisePropertyChanged(nameof(CanEdit)); // Обновляем состояние команды редактирования
|
||
this.RaisePropertyChanged(nameof(CanDelete)); // Обновляем состояние команды удаления
|
||
}
|
||
RefreshGroups(); // Обновляем список групп
|
||
}
|
||
|
||
// Обновление списка групп из UseCase.
|
||
private void RefreshGroups()
|
||
{
|
||
groupPresentersDataSource.Clear(); // Очищаем текущий список групп
|
||
foreach (var item in _groupUseCase.GetAllGroups())
|
||
{
|
||
GroupPresenter groupPresenter = new GroupPresenter
|
||
{
|
||
Id = item.Id,
|
||
Name = item.Name,
|
||
users = item.Users?.Select(user => new UserPresenter
|
||
{
|
||
Name = user.FIO,
|
||
Guid = user.Guid,
|
||
Group = new GroupPresenter { Id = item.Id, Name = item.Name }
|
||
}).ToList()
|
||
};
|
||
groupPresentersDataSource.Add(groupPresenter); // Добавляем группу в список
|
||
}
|
||
_groups = new ObservableCollection<GroupPresenter>(groupPresentersDataSource); // Обновляем коллекцию групп
|
||
}
|
||
}
|
||
}
|