MainForm.cs 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. using Npgsql;
  2. using TravelAgencyWinForms.Data;
  3. using TravelAgencyWinForms.Models;
  4. using TravelAgencyWinForms.Services;
  5. using TravelAgencyWinForms.Utils;
  6. namespace TravelAgencyWinForms.Forms;
  7. public partial class MainForm : Form
  8. {
  9. private Button? _activeMenuButton;
  10. public MainForm()
  11. {
  12. InitializeComponent();
  13. ApplyStyle();
  14. LoadBanner();
  15. BuildMenu();
  16. LoadDashboard();
  17. FormClosing += (_, _) => CurrentUser.Clear();
  18. }
  19. private void ApplyStyle()
  20. {
  21. AppTheme.ApplyForm(this);
  22. menuPanel.BackColor = Color.FromArgb(76, 150, 138);
  23. menuHeaderPanel.BackColor = Color.FromArgb(76, 150, 138);
  24. menuItemsPanel.BackColor = Color.FromArgb(76, 150, 138);
  25. appTitleLabel.ForeColor = Color.White;
  26. modeLabel.ForeColor = Color.FromArgb(227, 247, 242);
  27. loginLabel.ForeColor = Color.FromArgb(227, 247, 242);
  28. userNameLabel.ForeColor = Color.White;
  29. contentPanel.BackColor = AppTheme.Background;
  30. heroPanel.BackColor = AppTheme.Surface;
  31. heroTitleLabel.ForeColor = AppTheme.Text;
  32. heroSubtitleLabel.ForeColor = AppTheme.Muted;
  33. upcomingGroupBox.ForeColor = AppTheme.Text;
  34. bookingsGroupBox.ForeColor = AppTheme.Text;
  35. AppTheme.StyleGrid(upcomingGrid);
  36. AppTheme.StyleGrid(bookingsGrid);
  37. appTitleLabel.Text = "Турагентство";
  38. modeLabel.Text = CurrentUser.IsAdmin ? "Панель администратора" : "Личный кабинет клиента";
  39. loginLabel.Text = CurrentUser.Login;
  40. userNameLabel.Text = string.IsNullOrWhiteSpace(CurrentUser.ClientName) ? CurrentUser.Login : CurrentUser.ClientName;
  41. heroTitleLabel.Text = CurrentUser.IsAdmin ? "Панель управления" : "Личный кабинет";
  42. heroSubtitleLabel.Text = CurrentUser.IsAdmin
  43. ? "Быстрый доступ к данным, отчётам и журналу операций"
  44. : "Просмотр туров, расписания и своих бронирований";
  45. }
  46. private void LoadBanner()
  47. {
  48. var image = AppTheme.LoadImage("main_dashboard_banner.png");
  49. if (image != null)
  50. bannerPictureBox.Image = image;
  51. }
  52. private void BuildMenu()
  53. {
  54. menuItemsPanel.Controls.Clear();
  55. AddMenuButton("Главная", LoadDashboard, true);
  56. if (CurrentUser.IsAdmin)
  57. {
  58. AddSection("Данные");
  59. AddMenuButton("Клиенты", () => OpenTable(EntityConfigs.Clients, true));
  60. AddMenuButton("Должности", () => OpenTable(EntityConfigs.Positions, true));
  61. AddMenuButton("Сотрудники", () => OpenTable(EntityConfigs.Employees, true));
  62. AddMenuButton("Города", () => OpenTable(EntityConfigs.Cities, true));
  63. AddMenuButton("Туры", () => OpenTable(EntityConfigs.Tours, true));
  64. AddMenuButton("Маршруты", () => OpenTable(EntityConfigs.TourCities, true));
  65. AddMenuButton("Расписание", () => OpenTable(EntityConfigs.TourList, true));
  66. AddMenuButton("Бронирования", () => OpenTable(EntityConfigs.Bookings, true));
  67. AddSection("Отчёты");
  68. AddMenuButton("Сводка", () => new ReportsForm().ShowDialog(this));
  69. AddMenuButton("Просроченные", () => OpenTable(EntityConfigs.OverdueView, false));
  70. AddMenuButton("Журнал", () => OpenTable(EntityConfigs.AuditLog, false));
  71. AddSection("Сервис");
  72. AddMenuButton("Пользователи", () => OpenTable(EntityConfigs.AppUsers, true));
  73. }
  74. else
  75. {
  76. AddSection("Мои данные");
  77. AddMenuButton("Личные данные", () => OpenTable(EntityConfigs.ClientDetails, false));
  78. AddMenuButton("Бронирования", () => OpenTable(EntityConfigs.UserBookings, false));
  79. AddMenuButton("Просроченные", () => OpenTable(EntityConfigs.UserOverdue, false));
  80. AddSection("Справочники");
  81. AddMenuButton("Города", () => OpenTable(EntityConfigs.Cities, false));
  82. AddMenuButton("Туры", () => OpenTable(EntityConfigs.Tours, false));
  83. AddMenuButton("Расписание", () => OpenTable(EntityConfigs.TourScheduleView, false));
  84. AddMenuButton("Отчёты", () => new ReportsForm().ShowDialog(this));
  85. }
  86. AddSection(string.Empty);
  87. AddMenuButton("Выход", Close);
  88. }
  89. private void AddMenuButton(string text, Action action, bool selected = false)
  90. {
  91. var button = new Button
  92. {
  93. Text = text,
  94. Width = 220,
  95. Height = 38,
  96. Margin = new Padding(0, 3, 0, 3)
  97. };
  98. AppTheme.StyleMenuButton(button);
  99. if (selected)
  100. SetActiveMenuButton(button);
  101. button.Click += (_, _) =>
  102. {
  103. SetActiveMenuButton(button);
  104. action();
  105. };
  106. menuItemsPanel.Controls.Add(button);
  107. }
  108. private void SetActiveMenuButton(Button button)
  109. {
  110. if (_activeMenuButton != null)
  111. AppTheme.StyleMenuButton(_activeMenuButton);
  112. _activeMenuButton = button;
  113. button.BackColor = Color.FromArgb(98, 181, 166);
  114. }
  115. private void AddSection(string text)
  116. {
  117. if (string.IsNullOrWhiteSpace(text))
  118. {
  119. menuItemsPanel.Controls.Add(new Panel { Height = 12, Width = 220 });
  120. return;
  121. }
  122. var label = new Label
  123. {
  124. Text = text.ToUpperInvariant(),
  125. Width = 220,
  126. Height = 26,
  127. ForeColor = Color.FromArgb(216, 243, 237),
  128. Font = new Font("Segoe UI Semibold", 8.5F),
  129. Margin = new Padding(0, 14, 0, 2)
  130. };
  131. menuItemsPanel.Controls.Add(label);
  132. }
  133. private void OpenTable(EntityConfig config, bool canEdit)
  134. {
  135. using var form = new TableEditorForm(config, canEdit);
  136. form.ShowDialog(this);
  137. LoadDashboard();
  138. }
  139. private void LoadDashboard()
  140. {
  141. LoadStats();
  142. LoadDashboardTables();
  143. }
  144. private void LoadStats()
  145. {
  146. statsPanel.Controls.Clear();
  147. foreach (var card in LoadStatCards())
  148. statsPanel.Controls.Add(card);
  149. }
  150. private IEnumerable<Control> LoadStatCards()
  151. {
  152. if (CurrentUser.IsAdmin)
  153. {
  154. yield return AppTheme.CreateCard("Клиенты", ScalarInt("SELECT COUNT(*) FROM clients"));
  155. yield return AppTheme.CreateCard("Сотрудники", ScalarInt("SELECT COUNT(*) FROM employees"));
  156. yield return AppTheme.CreateCard("Туры", ScalarInt("SELECT COUNT(*) FROM tours"));
  157. yield return AppTheme.CreateCard("Бронирования", ScalarInt("SELECT COUNT(*) FROM bookings"));
  158. yield return AppTheme.CreateCard("Просроченные", ScalarInt("SELECT COUNT(*) FROM v_overdue_client_bookings"));
  159. }
  160. else
  161. {
  162. yield return AppTheme.CreateCard("Бронирования", ScalarInt("SELECT COUNT(*) FROM bookings WHERE client_id = @client_id", new NpgsqlParameter("client_id", CurrentUser.ClientId ?? -1)));
  163. yield return AppTheme.CreateCard("Просроченные", ScalarInt("SELECT COUNT(*) FROM v_overdue_client_bookings WHERE client_id = @client_id", new NpgsqlParameter("client_id", CurrentUser.ClientId ?? -1)));
  164. yield return AppTheme.CreateCard("Туры", ScalarInt("SELECT COUNT(*) FROM tours"));
  165. yield return AppTheme.CreateCard("Рейсы", ScalarInt("SELECT COUNT(*) FROM tour_list WHERE start_date >= CURRENT_DATE"), "будущие даты");
  166. }
  167. }
  168. private void LoadDashboardTables()
  169. {
  170. upcomingGrid.DataSource = Db.Query(@"
  171. SELECT
  172. tour_name AS ""Тур"",
  173. start_date AS ""Дата начала"",
  174. end_date AS ""Дата окончания"",
  175. duration_days AS ""Длительность"",
  176. price AS ""Стоимость""
  177. FROM v_tour_schedule
  178. WHERE start_date >= CURRENT_DATE
  179. ORDER BY start_date
  180. LIMIT 8;");
  181. bookingsGrid.DataSource = CurrentUser.IsAdmin
  182. ? Db.Query(@"
  183. SELECT
  184. booking_number AS ""Номер"",
  185. client_name AS ""Клиент"",
  186. employee_name AS ""Сотрудник"",
  187. tour_name AS ""Тур"",
  188. booking_date AS ""Дата оформления"",
  189. status AS ""Статус""
  190. FROM v_booking_details
  191. ORDER BY booking_date DESC, booking_id DESC
  192. LIMIT 8;")
  193. : Db.Query(@"
  194. SELECT
  195. booking_number AS ""Номер"",
  196. client_name AS ""Клиент"",
  197. tour_name AS ""Тур"",
  198. booking_date AS ""Дата оформления"",
  199. status AS ""Статус""
  200. FROM v_booking_details
  201. WHERE client_id = @client_id
  202. ORDER BY booking_date DESC, booking_id DESC
  203. LIMIT 8;", new NpgsqlParameter("client_id", CurrentUser.ClientId ?? -1));
  204. AppTheme.StyleGrid(upcomingGrid);
  205. AppTheme.StyleGrid(bookingsGrid);
  206. PresentationHelper.ApplyHeaders(upcomingGrid);
  207. PresentationHelper.ApplyHeaders(bookingsGrid);
  208. }
  209. private static string ScalarInt(string sql, params NpgsqlParameter[] parameters)
  210. {
  211. var result = Db.Scalar(sql, parameters);
  212. return Convert.ToInt32(result ?? 0).ToString();
  213. }
  214. }