| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501 |
- using CsvHelper;
- using Npgsql;
- using System;
- using System.Data;
- using System.Globalization;
- using System.IO;
- using System.Text;
- using System.Threading.Tasks;
- using System.Windows.Forms;
- namespace DeanOfficeApp
- {
- public partial class MainForm : Form
- {
- private readonly string _connString = "Host=245e1-rw.db.pub.dbaas.postgrespro.ru;Port=5432;Database=dbpractice;Username=mardasov_mv;Password=A4%2x$$2Ynr";
- private readonly string _userRole;
- public MainForm(string userRole, string username, string fullName)
- {
- InitializeComponent();
- _userRole = userRole;
- this.Text = $"Деканат - {fullName} ({userRole})";
- bool canEdit = (userRole == "admin" || userRole == "manager");
- gbDisciplines.Visible = canEdit;
- btnGrades.Visible = canEdit;
- btnAssignments.Visible = canEdit;
- numHours.Minimum = 1;
- numHours.Maximum = 1000;
- numHours.Value = numHours.Minimum;
- // Подписываемся на события (если в дизайнере не подписаны)
- cmbGroups.SelectedIndexChanged += cmbGroups_SelectedIndexChanged;
- rbAsc.CheckedChanged += rbSort_CheckedChanged;
- rbDesc.CheckedChanged += rbSort_CheckedChanged;
- // Асинхронная загрузка начальных данных
- _ = LoadInitialDataAsync();
- }
- private async Task LoadInitialDataAsync()
- {
- try
- {
- Cursor = Cursors.WaitCursor;
- await LoadGroupsAsync();
- if (_userRole == "admin" || _userRole == "manager")
- {
- await LoadDisciplinesAsync();
- await LoadTeachersAsync();
- }
- }
- finally
- {
- Cursor = Cursors.Default;
- }
- }
- private async Task LoadGroupsAsync()
- {
- try
- {
- using (var conn = new NpgsqlConnection(_connString))
- {
- await conn.OpenAsync();
- var cmd = new NpgsqlCommand("SELECT group_id, name FROM \"Group\" ORDER BY name", conn);
- var dt = new DataTable();
- dt.Load(await cmd.ExecuteReaderAsync());
- cmbGroups.DisplayMember = "name";
- cmbGroups.ValueMember = "group_id";
- cmbGroups.DataSource = dt;
- if (cmbGroups.Items.Count > 0)
- cmbGroups.SelectedIndex = 0; // автоматически выбрать первую группу
- }
- }
- catch (Exception ex)
- {
- MessageBox.Show($"Ошибка загрузки групп: {ex.Message}");
- }
- }
- private async Task LoadTeachersAsync()
- {
- try
- {
- using (var conn = new NpgsqlConnection(_connString))
- {
- await conn.OpenAsync();
- var cmd = new NpgsqlCommand("SELECT teacher_id, full_name FROM Teacher ORDER BY full_name", conn);
- var dt = new DataTable();
- dt.Load(await cmd.ExecuteReaderAsync());
- cmbTeachers.DisplayMember = "full_name";
- cmbTeachers.ValueMember = "teacher_id";
- cmbTeachers.DataSource = dt;
- if (cmbTeachers.Items.Count > 0)
- cmbTeachers.SelectedIndex = 0;
- }
- }
- catch (Exception ex)
- {
- MessageBox.Show($"Ошибка загрузки преподавателей: {ex.Message}");
- }
- }
- private async Task LoadDisciplinesAsync()
- {
- try
- {
- using (var conn = new NpgsqlConnection(_connString))
- {
- await conn.OpenAsync();
- var cmd = new NpgsqlCommand("SELECT discipline_id, name, hours FROM Discipline ORDER BY name", conn);
- var dt = new DataTable();
- dt.Load(await cmd.ExecuteReaderAsync());
- dgvDisciplines.DataSource = dt;
- if (dgvDisciplines.Columns.Contains("discipline_id"))
- dgvDisciplines.Columns["discipline_id"].Visible = false;
- }
- dgvDisciplines.ClearSelection();
- txtDiscName.Clear();
- numHours.Value = numHours.Minimum;
- await RefreshScheduleAsync();
- }
- catch (Exception ex)
- {
- MessageBox.Show($"Ошибка загрузки дисциплин: {ex.Message}");
- }
- }
- private async Task RefreshScheduleAsync()
- {
- if (cmbGroups.SelectedValue != null)
- await LoadScheduleAsync((int)cmbGroups.SelectedValue);
- }
- private async Task LoadScheduleAsync(int groupId)
- {
- // Безопасная сортировка: проверяем, что выбранное значение допустимо
- string sortDirection = rbAsc.Checked ? "ASC" : "DESC";
- // Используем параметризованный запрос, но ORDER BY нельзя параметризовать,
- // поэтому проверяем значение перед вставкой.
- if (sortDirection != "ASC" && sortDirection != "DESC")
- sortDirection = "ASC";
- string query = $@"
- SELECT d.name AS Дисциплина, d.hours AS Часы, t.full_name AS Преподаватель
- FROM Assignment a
- JOIN Discipline d ON a.discipline_id = d.discipline_id
- JOIN Teacher t ON a.teacher_id = t.teacher_id
- WHERE a.group_id = @gid
- ORDER BY d.hours {sortDirection}";
- try
- {
- Cursor = Cursors.WaitCursor;
- using (var conn = new NpgsqlConnection(_connString))
- {
- await conn.OpenAsync();
- using (var cmd = new NpgsqlCommand(query, conn))
- {
- cmd.Parameters.AddWithValue("@gid", groupId);
- var dt = new DataTable();
- dt.Load(await cmd.ExecuteReaderAsync());
- dgvSchedule.DataSource = dt;
- }
- }
- }
- catch (Exception ex)
- {
- MessageBox.Show($"Ошибка загрузки расписания: {ex.Message}");
- }
- finally
- {
- Cursor = Cursors.Default;
- }
- }
- // Обработчик выбора группы
- private async void cmbGroups_SelectedIndexChanged(object sender, EventArgs e)
- {
- await RefreshScheduleAsync();
- }
- // Обработчик изменения сортировки
- private async void rbSort_CheckedChanged(object sender, EventArgs e)
- {
- await RefreshScheduleAsync();
- }
- // Кнопка "Загрузить расписание" (можно оставить для ручного обновления)
- private async void btnLoad_Click(object sender, EventArgs e)
- {
- await RefreshScheduleAsync();
- }
- private async void btnAdd_Click(object sender, EventArgs e)
- {
- if (string.IsNullOrWhiteSpace(txtDiscName.Text))
- {
- MessageBox.Show("Введите название дисциплины.");
- return;
- }
- if (numHours.Value < numHours.Minimum)
- {
- MessageBox.Show($"Количество часов должно быть не менее {numHours.Minimum}.");
- return;
- }
- if (cmbGroups.SelectedValue == null)
- {
- MessageBox.Show("Выберите группу, к которой будет привязана дисциплина.");
- return;
- }
- if (cmbTeachers.SelectedValue == null)
- {
- MessageBox.Show("Выберите преподавателя.");
- return;
- }
- int groupId = (int)cmbGroups.SelectedValue;
- int teacherId = (int)cmbTeachers.SelectedValue;
- string discName = txtDiscName.Text.Trim();
- int hours = (int)numHours.Value;
- try
- {
- Cursor = Cursors.WaitCursor;
- using (var conn = new NpgsqlConnection(_connString))
- {
- await conn.OpenAsync();
- var cmdInsert = new NpgsqlCommand(
- "INSERT INTO Discipline (name, hours) VALUES (@n, @h) RETURNING discipline_id", conn);
- cmdInsert.Parameters.AddWithValue("@n", discName);
- cmdInsert.Parameters.AddWithValue("@h", hours);
- int newDisciplineId = (int)await cmdInsert.ExecuteScalarAsync();
- var cmdAssign = new NpgsqlCommand(
- "INSERT INTO Assignment (group_id, discipline_id, teacher_id, semester) VALUES (@g, @d, @t, 1)", conn);
- cmdAssign.Parameters.AddWithValue("@g", groupId);
- cmdAssign.Parameters.AddWithValue("@d", newDisciplineId);
- cmdAssign.Parameters.AddWithValue("@t", teacherId);
- await cmdAssign.ExecuteNonQueryAsync();
- }
- await LoadDisciplinesAsync();
- txtDiscName.Clear();
- numHours.Value = numHours.Minimum;
- MessageBox.Show("Дисциплина добавлена и привязана к группе и преподавателю.");
- }
- catch (Exception ex)
- {
- MessageBox.Show($"Ошибка: {ex.Message}");
- }
- finally
- {
- Cursor = Cursors.Default;
- }
- }
- private async void btnUpdate_Click(object sender, EventArgs e)
- {
- if (dgvDisciplines.CurrentRow == null)
- {
- MessageBox.Show("Выберите дисциплину для обновления.");
- return;
- }
- int id = (int)dgvDisciplines.CurrentRow.Cells["discipline_id"].Value;
- if (string.IsNullOrWhiteSpace(txtDiscName.Text))
- {
- MessageBox.Show("Введите название.");
- return;
- }
- if (numHours.Value < numHours.Minimum)
- {
- MessageBox.Show($"Количество часов должно быть не менее {numHours.Minimum}.");
- return;
- }
- try
- {
- Cursor = Cursors.WaitCursor;
- using (var conn = new NpgsqlConnection(_connString))
- {
- await conn.OpenAsync();
- var cmd = new NpgsqlCommand("UPDATE Discipline SET name=@n, hours=@h WHERE discipline_id=@id", conn);
- cmd.Parameters.AddWithValue("@n", txtDiscName.Text.Trim());
- cmd.Parameters.AddWithValue("@h", (int)numHours.Value);
- cmd.Parameters.AddWithValue("@id", id);
- await cmd.ExecuteNonQueryAsync();
- }
- await LoadDisciplinesAsync();
- MessageBox.Show("Дисциплина обновлена.");
- }
- catch (Exception ex)
- {
- MessageBox.Show($"Ошибка: {ex.Message}");
- }
- finally
- {
- Cursor = Cursors.Default;
- }
- }
- private async void btnDelete_Click(object sender, EventArgs e)
- {
- if (dgvDisciplines.CurrentRow == null)
- {
- MessageBox.Show("Выберите дисциплину для удаления.");
- return;
- }
- int id = (int)dgvDisciplines.CurrentRow.Cells["discipline_id"].Value;
- if (MessageBox.Show("Удалить дисциплину? Это также удалит все её связи (Assignment).",
- "Подтверждение", MessageBoxButtons.YesNo) == DialogResult.Yes)
- {
- try
- {
- Cursor = Cursors.WaitCursor;
- using (var conn = new NpgsqlConnection(_connString))
- {
- await conn.OpenAsync();
- var delAssign = new NpgsqlCommand("DELETE FROM Assignment WHERE discipline_id = @id", conn);
- delAssign.Parameters.AddWithValue("@id", id);
- await delAssign.ExecuteNonQueryAsync();
- var delDisc = new NpgsqlCommand("DELETE FROM Discipline WHERE discipline_id = @id", conn);
- delDisc.Parameters.AddWithValue("@id", id);
- await delDisc.ExecuteNonQueryAsync();
- }
- await LoadDisciplinesAsync();
- txtDiscName.Clear();
- numHours.Value = numHours.Minimum;
- MessageBox.Show("Дисциплина и связанные назначения удалены.");
- }
- catch (Exception ex)
- {
- MessageBox.Show($"Ошибка: {ex.Message}");
- }
- finally
- {
- Cursor = Cursors.Default;
- }
- }
- }
- private void btnExportCsv_Click(object sender, EventArgs e)
- {
- if (dgvSchedule.Rows.Count == 0)
- {
- MessageBox.Show("Нет данных для экспорта.");
- return;
- }
- using (var sfd = new SaveFileDialog() { Filter = "CSV|*.csv", FileName = "schedule.csv" })
- {
- if (sfd.ShowDialog() == DialogResult.OK)
- {
- using (var writer = new StreamWriter(sfd.FileName, false, Encoding.UTF8))
- using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture))
- {
- foreach (DataGridViewColumn col in dgvSchedule.Columns)
- csv.WriteField(col.HeaderText);
- csv.NextRecord();
- foreach (DataGridViewRow row in dgvSchedule.Rows)
- {
- if (!row.IsNewRow)
- {
- foreach (DataGridViewCell cell in row.Cells)
- csv.WriteField(cell.Value?.ToString() ?? "");
- csv.NextRecord();
- }
- }
- }
- MessageBox.Show("CSV сохранён.");
- }
- }
- }
- private void btnExportHtml_Click(object sender, EventArgs e)
- {
- if (dgvSchedule.Rows.Count == 0)
- {
- MessageBox.Show("Нет данных для формирования отчёта.");
- return;
- }
- using (var sfd = new SaveFileDialog() { Filter = "HTML files (*.html)|*.html", FileName = $"report_{cmbGroups.Text}.html" })
- {
- if (sfd.ShowDialog() == DialogResult.OK)
- {
- string groupName = cmbGroups.Text.Trim();
- string currentDate = DateTime.Now.ToString("dd.MM.yyyy HH:mm:ss");
- int disciplinesCount = dgvSchedule.Rows.Count;
- StringBuilder sb = new StringBuilder();
- sb.AppendLine("<!DOCTYPE html><html><head><meta charset='UTF-8'><title>Отчёт</title>");
- sb.AppendLine("<style>table{border-collapse:collapse;width:100%}th,td{border:1px solid #ddd;padding:8px}th{background:#4CAF50;color:#fff}</style>");
- sb.AppendLine("</head><body>");
- sb.AppendLine($"<h2>Группа {groupName}</h2><p>Дата: {currentDate}</p><p>Всего дисциплин: {disciplinesCount}</p>");
- sb.AppendLine("<table border='1'>");
- sb.AppendLine("<tr><th>Дисциплина</th><th>Часы</th><th>Преподаватель</th></tr>");
- foreach (DataGridViewRow row in dgvSchedule.Rows)
- {
- if (!row.IsNewRow)
- {
- sb.AppendLine("<tr>");
- foreach (DataGridViewCell cell in row.Cells)
- sb.AppendLine($"<td>{cell.Value}</td>");
- sb.AppendLine("</tr>");
- }
- }
- sb.AppendLine("</table></body></html>");
- File.WriteAllText(sfd.FileName, sb.ToString(), Encoding.UTF8);
- MessageBox.Show("HTML-отчёт успешно сохранён!", "Успех", MessageBoxButtons.OK, MessageBoxIcon.Information);
- }
- }
- }
- private void dgvDisciplines_SelectionChanged(object sender, EventArgs e)
- {
- if (dgvDisciplines.CurrentRow != null && dgvDisciplines.CurrentRow.Cells["name"].Value != null)
- {
- txtDiscName.Text = dgvDisciplines.CurrentRow.Cells["name"].Value.ToString();
- if (dgvDisciplines.CurrentRow.Cells["hours"].Value != null && dgvDisciplines.CurrentRow.Cells["hours"].Value != DBNull.Value)
- {
- int hours = Convert.ToInt32(dgvDisciplines.CurrentRow.Cells["hours"].Value);
- if (hours >= numHours.Minimum && hours <= numHours.Maximum)
- numHours.Value = hours;
- else if (hours < numHours.Minimum)
- numHours.Value = numHours.Minimum;
- else
- numHours.Value = numHours.Maximum;
- }
- else
- numHours.Value = numHours.Minimum;
- }
- else
- {
- txtDiscName.Clear();
- numHours.Value = numHours.Minimum;
- }
- }
- private void controlBox_Click(object sender, EventArgs e) => Application.Exit();
- private void gbDisciplines_Click(object sender, EventArgs e) { }
- private void panelRight_Paint(object sender, PaintEventArgs e) { }
- private void cmbTeachers_SelectedIndexChanged(object sender, EventArgs e) { }
- private void btnStudents_Click(object sender, EventArgs e)
- {
- if (_userRole == "admin" || _userRole == "manager")
- {
- StudentForm studentForm = new StudentForm();
- studentForm.ShowDialog();
- }
- else
- {
- MessageBox.Show("Доступ запрещён. Только для администраторов и менеджеров.", "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Warning);
- }
- }
- private void btnUsers_Click(object sender, EventArgs e)
- {
- if (_userRole == "admin")
- {
- UserManagementForm f = new UserManagementForm();
- f.ShowDialog();
- }
- else
- {
- MessageBox.Show("Доступ запрещён. Только для администратора.", "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Warning);
- }
- }
- private void btnGrades_Click(object sender, EventArgs e)
- {
- if (_userRole == "admin" || _userRole == "manager")
- {
- GradeForm gradeForm = new GradeForm();
- gradeForm.ShowDialog();
- }
- else
- {
- MessageBox.Show("Доступ запрещён. Только для администраторов и менеджеров.", "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Warning);
- }
- }
- private void btnAssignments_Click(object sender, EventArgs e)
- {
- if (_userRole == "admin" || _userRole == "manager")
- {
- AssignmentForm assignmentForm = new AssignmentForm();
- assignmentForm.ShowDialog();
- }
- else
- {
- MessageBox.Show("Доступ запрещён. Только для администраторов и менеджеров.", "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Warning);
- }
- }
- }
- }
|