AssignmentForm.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397
  1. using Guna.UI2.WinForms;
  2. using Npgsql;
  3. using System;
  4. using System.Data;
  5. using System.Threading.Tasks;
  6. using System.Windows.Forms;
  7. using System.Linq;
  8. namespace DeanOfficeApp
  9. {
  10. public partial class AssignmentForm : Form
  11. {
  12. private readonly string _connString = "Host=245e1-rw.db.pub.dbaas.postgrespro.ru;Port=5432;Database=dbpractice;Username=mardasov_mv;Password=A4%2x$$2Ynr";
  13. private DataTable _assignmentsTable;
  14. public AssignmentForm()
  15. {
  16. InitializeComponent();
  17. this.Load += AssignmentForm_Load;
  18. }
  19. private async void AssignmentForm_Load(object sender, EventArgs e)
  20. {
  21. await LoadAllDataAsync();
  22. }
  23. private async Task LoadAllDataAsync()
  24. {
  25. try
  26. {
  27. Cursor = Cursors.WaitCursor;
  28. await Task.WhenAll(
  29. LoadGroupsAsync(),
  30. LoadDisciplinesAsync(),
  31. LoadTeachersAsync(),
  32. LoadAssignmentsAsync()
  33. );
  34. }
  35. finally
  36. {
  37. Cursor = Cursors.Default;
  38. }
  39. }
  40. private async Task LoadGroupsAsync()
  41. {
  42. try
  43. {
  44. using (var conn = new NpgsqlConnection(_connString))
  45. {
  46. await conn.OpenAsync();
  47. string sql = "SELECT group_id, name FROM \"Group\" ORDER BY name";
  48. using (var cmd = new NpgsqlCommand(sql, conn))
  49. using (var reader = await cmd.ExecuteReaderAsync())
  50. {
  51. var dt = new DataTable();
  52. dt.Load(reader);
  53. cmbGroup.DisplayMember = "name";
  54. cmbGroup.ValueMember = "group_id";
  55. cmbGroup.DataSource = dt;
  56. cmbGroup.SelectedIndex = -1;
  57. }
  58. }
  59. }
  60. catch (Exception ex)
  61. {
  62. MessageBox.Show($"Ошибка загрузки групп: {ex.Message}");
  63. }
  64. }
  65. private async Task LoadDisciplinesAsync()
  66. {
  67. try
  68. {
  69. using (var conn = new NpgsqlConnection(_connString))
  70. {
  71. await conn.OpenAsync();
  72. string sql = "SELECT discipline_id, name FROM Discipline ORDER BY name";
  73. using (var cmd = new NpgsqlCommand(sql, conn))
  74. using (var reader = await cmd.ExecuteReaderAsync())
  75. {
  76. var dt = new DataTable();
  77. dt.Load(reader);
  78. cmbDiscipline.DisplayMember = "name";
  79. cmbDiscipline.ValueMember = "discipline_id";
  80. cmbDiscipline.DataSource = dt;
  81. cmbDiscipline.SelectedIndex = -1;
  82. }
  83. }
  84. }
  85. catch (Exception ex)
  86. {
  87. MessageBox.Show($"Ошибка загрузки дисциплин: {ex.Message}");
  88. }
  89. }
  90. private async Task LoadTeachersAsync()
  91. {
  92. try
  93. {
  94. using (var conn = new NpgsqlConnection(_connString))
  95. {
  96. await conn.OpenAsync();
  97. string sql = "SELECT teacher_id, full_name FROM Teacher ORDER BY full_name";
  98. using (var cmd = new NpgsqlCommand(sql, conn))
  99. using (var reader = await cmd.ExecuteReaderAsync())
  100. {
  101. var dt = new DataTable();
  102. dt.Load(reader);
  103. cmbTeacher.DisplayMember = "full_name";
  104. cmbTeacher.ValueMember = "teacher_id";
  105. cmbTeacher.DataSource = dt;
  106. cmbTeacher.SelectedIndex = -1;
  107. }
  108. }
  109. }
  110. catch (Exception ex)
  111. {
  112. MessageBox.Show($"Ошибка загрузки преподавателей: {ex.Message}");
  113. }
  114. }
  115. private async Task LoadAssignmentsAsync()
  116. {
  117. string sql = @"
  118. SELECT a.assignment_id, g.name AS group_name, d.name AS discipline_name,
  119. t.full_name AS teacher_name, a.semester
  120. FROM Assignment a
  121. JOIN ""Group"" g ON a.group_id = g.group_id
  122. JOIN Discipline d ON a.discipline_id = d.discipline_id
  123. JOIN Teacher t ON a.teacher_id = t.teacher_id
  124. ORDER BY g.name, a.semester, d.name";
  125. try
  126. {
  127. using (var conn = new NpgsqlConnection(_connString))
  128. {
  129. await conn.OpenAsync();
  130. using (var cmd = new NpgsqlCommand(sql, conn))
  131. using (var reader = await cmd.ExecuteReaderAsync())
  132. {
  133. _assignmentsTable = new DataTable();
  134. _assignmentsTable.Load(reader);
  135. ApplyFilter();
  136. }
  137. }
  138. }
  139. catch (Exception ex)
  140. {
  141. MessageBox.Show($"Ошибка загрузки назначений: {ex.Message}");
  142. }
  143. }
  144. private void ApplyFilter()
  145. {
  146. if (_assignmentsTable == null) return;
  147. string filterText = txtSearch.Text.Trim().ToLower();
  148. if (string.IsNullOrEmpty(filterText))
  149. {
  150. dgvAssignments.DataSource = _assignmentsTable;
  151. }
  152. else
  153. {
  154. var filteredRows = _assignmentsTable.AsEnumerable()
  155. .Where(row => row["group_name"].ToString().ToLower().Contains(filterText) ||
  156. row["discipline_name"].ToString().ToLower().Contains(filterText) ||
  157. row["teacher_name"].ToString().ToLower().Contains(filterText) ||
  158. row["semester"].ToString().Contains(filterText))
  159. .CopyToDataTable();
  160. dgvAssignments.DataSource = filteredRows;
  161. }
  162. if (dgvAssignments.Columns.Contains("assignment_id"))
  163. dgvAssignments.Columns["assignment_id"].Visible = false;
  164. }
  165. private async void btnAdd_Click(object sender, EventArgs e)
  166. {
  167. if (!ValidateInput()) return;
  168. string sql = @"
  169. INSERT INTO Assignment (group_id, discipline_id, teacher_id, semester)
  170. VALUES (@g, @d, @t, @s)";
  171. try
  172. {
  173. Cursor = Cursors.WaitCursor;
  174. using (var conn = new NpgsqlConnection(_connString))
  175. {
  176. await conn.OpenAsync();
  177. using (var cmd = new NpgsqlCommand(sql, conn))
  178. {
  179. cmd.Parameters.AddWithValue("@g", (int)cmbGroup.SelectedValue);
  180. cmd.Parameters.AddWithValue("@d", (int)cmbDiscipline.SelectedValue);
  181. cmd.Parameters.AddWithValue("@t", (int)cmbTeacher.SelectedValue);
  182. cmd.Parameters.AddWithValue("@s", (int)cmbSemester.SelectedItem);
  183. await cmd.ExecuteNonQueryAsync();
  184. }
  185. }
  186. await LoadAssignmentsAsync();
  187. ClearFields();
  188. MessageBox.Show("Назначение добавлено.");
  189. }
  190. catch (PostgresException ex) when (ex.SqlState == "23505")
  191. {
  192. MessageBox.Show("Такое назначение уже существует (группа + дисциплина + семестр).");
  193. }
  194. catch (Exception ex)
  195. {
  196. MessageBox.Show($"Ошибка: {ex.Message}");
  197. }
  198. finally { Cursor = Cursors.Default; }
  199. }
  200. private async void btnUpdate_Click(object sender, EventArgs e)
  201. {
  202. if (dgvAssignments.CurrentRow == null)
  203. {
  204. MessageBox.Show("Выберите назначение для редактирования.");
  205. return;
  206. }
  207. if (!ValidateInput()) return;
  208. int assignmentId = (int)dgvAssignments.CurrentRow.Cells["assignment_id"].Value;
  209. if (await HasGradesAsync(assignmentId))
  210. {
  211. MessageBox.Show("Нельзя изменить назначение, по которому уже есть оценки.", "Ограничение", MessageBoxButtons.OK, MessageBoxIcon.Warning);
  212. return;
  213. }
  214. string sql = @"
  215. UPDATE Assignment
  216. SET group_id = @g, discipline_id = @d, teacher_id = @t, semester = @s
  217. WHERE assignment_id = @id";
  218. try
  219. {
  220. Cursor = Cursors.WaitCursor;
  221. using (var conn = new NpgsqlConnection(_connString))
  222. {
  223. await conn.OpenAsync();
  224. using (var cmd = new NpgsqlCommand(sql, conn))
  225. {
  226. cmd.Parameters.AddWithValue("@g", (int)cmbGroup.SelectedValue);
  227. cmd.Parameters.AddWithValue("@d", (int)cmbDiscipline.SelectedValue);
  228. cmd.Parameters.AddWithValue("@t", (int)cmbTeacher.SelectedValue);
  229. cmd.Parameters.AddWithValue("@s", (int)cmbSemester.SelectedItem);
  230. cmd.Parameters.AddWithValue("@id", assignmentId);
  231. await cmd.ExecuteNonQueryAsync();
  232. }
  233. }
  234. await LoadAssignmentsAsync();
  235. ClearFields();
  236. MessageBox.Show("Назначение обновлено.");
  237. }
  238. catch (PostgresException ex) when (ex.SqlState == "23505")
  239. {
  240. MessageBox.Show("Конфликт: такое назначение уже существует.");
  241. }
  242. catch (Exception ex)
  243. {
  244. MessageBox.Show($"Ошибка: {ex.Message}");
  245. }
  246. finally { Cursor = Cursors.Default; }
  247. }
  248. private async void btnDelete_Click(object sender, EventArgs e)
  249. {
  250. if (dgvAssignments.CurrentRow == null)
  251. {
  252. MessageBox.Show("Выберите назначение для удаления.");
  253. return;
  254. }
  255. int id = (int)dgvAssignments.CurrentRow.Cells["assignment_id"].Value;
  256. if (await HasGradesAsync(id))
  257. {
  258. MessageBox.Show("Нельзя удалить назначение, по которому уже есть оценки.", "Ограничение", MessageBoxButtons.OK, MessageBoxIcon.Warning);
  259. return;
  260. }
  261. if (MessageBox.Show("Удалить назначение?", "Подтверждение", MessageBoxButtons.YesNo) != DialogResult.Yes)
  262. return;
  263. string sql = "DELETE FROM Assignment WHERE assignment_id = @id";
  264. try
  265. {
  266. Cursor = Cursors.WaitCursor;
  267. using (var conn = new NpgsqlConnection(_connString))
  268. {
  269. await conn.OpenAsync();
  270. using (var cmd = new NpgsqlCommand(sql, conn))
  271. {
  272. cmd.Parameters.AddWithValue("@id", id);
  273. await cmd.ExecuteNonQueryAsync();
  274. }
  275. }
  276. await LoadAssignmentsAsync();
  277. ClearFields();
  278. MessageBox.Show("Назначение удалено.");
  279. }
  280. catch (Exception ex)
  281. {
  282. MessageBox.Show($"Ошибка: {ex.Message}");
  283. }
  284. finally { Cursor = Cursors.Default; }
  285. }
  286. private async Task<bool> HasGradesAsync(int assignmentId)
  287. {
  288. string sql = @"
  289. SELECT COUNT(*) FROM Progress p
  290. JOIN Assignment a ON p.discipline_id = a.discipline_id
  291. WHERE a.assignment_id = @id";
  292. try
  293. {
  294. using (var conn = new NpgsqlConnection(_connString))
  295. {
  296. await conn.OpenAsync();
  297. using (var cmd = new NpgsqlCommand(sql, conn))
  298. {
  299. cmd.Parameters.AddWithValue("@id", assignmentId);
  300. long count = (long)await cmd.ExecuteScalarAsync();
  301. return count > 0;
  302. }
  303. }
  304. }
  305. catch
  306. {
  307. return false;
  308. }
  309. }
  310. private async void btnRefresh_Click(object sender, EventArgs e)
  311. {
  312. await LoadAssignmentsAsync();
  313. ClearFields();
  314. }
  315. private void txtSearch_TextChanged(object sender, EventArgs e)
  316. {
  317. ApplyFilter();
  318. }
  319. private void dgvAssignments_SelectionChanged(object sender, EventArgs e)
  320. {
  321. if (dgvAssignments.CurrentRow == null) return;
  322. string groupName = dgvAssignments.CurrentRow.Cells["group_name"].Value?.ToString();
  323. string disciplineName = dgvAssignments.CurrentRow.Cells["discipline_name"].Value?.ToString();
  324. string teacherName = dgvAssignments.CurrentRow.Cells["teacher_name"].Value?.ToString();
  325. int semester = Convert.ToInt32(dgvAssignments.CurrentRow.Cells["semester"].Value);
  326. SelectComboBoxItemByText(cmbGroup, groupName);
  327. SelectComboBoxItemByText(cmbDiscipline, disciplineName);
  328. SelectComboBoxItemByText(cmbTeacher, teacherName);
  329. cmbSemester.SelectedItem = semester.ToString();
  330. }
  331. private void SelectComboBoxItemByText(Guna2ComboBox comboBox, string text)
  332. {
  333. if (string.IsNullOrEmpty(text) || comboBox.DataSource == null) return;
  334. foreach (DataRowView row in comboBox.Items)
  335. {
  336. string displayText = row[comboBox.DisplayMember].ToString();
  337. if (displayText == text)
  338. {
  339. comboBox.SelectedItem = row;
  340. break;
  341. }
  342. }
  343. }
  344. private bool ValidateInput()
  345. {
  346. if (cmbGroup.SelectedValue == null || cmbDiscipline.SelectedValue == null ||
  347. cmbTeacher.SelectedValue == null || cmbSemester.SelectedItem == null)
  348. {
  349. MessageBox.Show("Заполните все поля (группа, дисциплина, преподаватель, семестр).");
  350. return false;
  351. }
  352. return true;
  353. }
  354. private void ClearFields()
  355. {
  356. cmbGroup.SelectedIndex = -1;
  357. cmbDiscipline.SelectedIndex = -1;
  358. cmbTeacher.SelectedIndex = -1;
  359. cmbSemester.SelectedIndex = 0;
  360. txtSearch.Clear();
  361. }
  362. }
  363. }