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); // Обновляем коллекцию групп
|
|||
|
}
|
|||
|
}
|
|||
|
}
|