diff --git a/ProjectHorseRacingOrg/FormHorseRacing.Designer.cs b/ProjectHorseRacingOrg/FormHorseRacing.Designer.cs index ef5bff8..3857407 100644 --- a/ProjectHorseRacingOrg/FormHorseRacing.Designer.cs +++ b/ProjectHorseRacingOrg/FormHorseRacing.Designer.cs @@ -37,6 +37,9 @@ RacingHorsesToolStripMenuItem = new ToolStripMenuItem(); RaceEntryDetalisToolStripMenuItem = new ToolStripMenuItem(); ReportsToolStripMenuItem = new ToolStripMenuItem(); + DirectoryReportToolStripMenuItem = new ToolStripMenuItem(); + raceReportToolStripMenuItem = new ToolStripMenuItem(); + raceDistributionToolStripMenuItem = new ToolStripMenuItem(); menuStrip1.SuspendLayout(); SuspendLayout(); // @@ -60,21 +63,21 @@ // JockeysToolStripMenuItem // JockeysToolStripMenuItem.Name = "JockeysToolStripMenuItem"; - JockeysToolStripMenuItem.Size = new Size(224, 26); + JockeysToolStripMenuItem.Size = new Size(195, 26); JockeysToolStripMenuItem.Text = "Жокеи"; JockeysToolStripMenuItem.Click += JockeysToolStripMenuItem_Click; // // HorsesToolStripMenuItem // HorsesToolStripMenuItem.Name = "HorsesToolStripMenuItem"; - HorsesToolStripMenuItem.Size = new Size(224, 26); + HorsesToolStripMenuItem.Size = new Size(195, 26); HorsesToolStripMenuItem.Text = "Лошади"; HorsesToolStripMenuItem.Click += HorsesToolStripMenuItem_Click; // // RacesToolStripMenuItem // RacesToolStripMenuItem.Name = "RacesToolStripMenuItem"; - RacesToolStripMenuItem.Size = new Size(224, 26); + RacesToolStripMenuItem.Size = new Size(195, 26); RacesToolStripMenuItem.Text = "Соревнования"; RacesToolStripMenuItem.Click += RacesToolStripMenuItem_Click; // @@ -88,23 +91,48 @@ // RacingHorsesToolStripMenuItem // RacingHorsesToolStripMenuItem.Name = "RacingHorsesToolStripMenuItem"; - RacingHorsesToolStripMenuItem.Size = new Size(224, 26); + RacingHorsesToolStripMenuItem.Size = new Size(218, 26); RacingHorsesToolStripMenuItem.Text = "Участие лошадей"; RacingHorsesToolStripMenuItem.Click += RacingHorsesToolStripMenuItem_Click; // // RaceEntryDetalisToolStripMenuItem // RaceEntryDetalisToolStripMenuItem.Name = "RaceEntryDetalisToolStripMenuItem"; - RaceEntryDetalisToolStripMenuItem.Size = new Size(224, 26); + RaceEntryDetalisToolStripMenuItem.Size = new Size(218, 26); RaceEntryDetalisToolStripMenuItem.Text = "Заявки на участие"; RaceEntryDetalisToolStripMenuItem.Click += RaceEntryDetalisToolStripMenuItem_Click; // // ReportsToolStripMenuItem // + ReportsToolStripMenuItem.DropDownItems.AddRange(new ToolStripItem[] { DirectoryReportToolStripMenuItem, raceReportToolStripMenuItem, raceDistributionToolStripMenuItem }); ReportsToolStripMenuItem.Name = "ReportsToolStripMenuItem"; ReportsToolStripMenuItem.Size = new Size(73, 24); ReportsToolStripMenuItem.Text = "Отчеты"; // + // DirectoryReportToolStripMenuItem + // + DirectoryReportToolStripMenuItem.Name = "DirectoryReportToolStripMenuItem"; + DirectoryReportToolStripMenuItem.ShortcutKeys = Keys.Control | Keys.W; + DirectoryReportToolStripMenuItem.Size = new Size(355, 26); + DirectoryReportToolStripMenuItem.Text = "Документ со справочниками"; + DirectoryReportToolStripMenuItem.Click += DirectoryReportToolStripMenuItem_Click; + // + // raceReportToolStripMenuItem + // + raceReportToolStripMenuItem.Name = "raceReportToolStripMenuItem"; + raceReportToolStripMenuItem.ShortcutKeys = Keys.Control | Keys.E; + raceReportToolStripMenuItem.Size = new Size(355, 26); + raceReportToolStripMenuItem.Text = "Движение соревнований"; + raceReportToolStripMenuItem.Click += RaceReportToolStripMenuItem_Click; + // + // raceDistributionToolStripMenuItem + // + raceDistributionToolStripMenuItem.Name = "raceDistributionToolStripMenuItem"; + raceDistributionToolStripMenuItem.ShortcutKeys = Keys.Control | Keys.P; + raceDistributionToolStripMenuItem.Size = new Size(355, 26); + raceDistributionToolStripMenuItem.Text = "Распределение соревнований"; + raceDistributionToolStripMenuItem.Click += RaceDistributionToolStripMenuItem_Click; + // // FormHorseRacing // AutoScaleDimensions = new SizeF(8F, 20F); @@ -133,5 +161,8 @@ private ToolStripMenuItem ReportsToolStripMenuItem; private ToolStripMenuItem RacingHorsesToolStripMenuItem; private ToolStripMenuItem RaceEntryDetalisToolStripMenuItem; + private ToolStripMenuItem DirectoryReportToolStripMenuItem; + private ToolStripMenuItem raceReportToolStripMenuItem; + private ToolStripMenuItem raceDistributionToolStripMenuItem; } } diff --git a/ProjectHorseRacingOrg/FormHorseRacing.cs b/ProjectHorseRacingOrg/FormHorseRacing.cs index 00437b6..bb60e02 100644 --- a/ProjectHorseRacingOrg/FormHorseRacing.cs +++ b/ProjectHorseRacingOrg/FormHorseRacing.cs @@ -8,11 +8,11 @@ namespace ProjectHorseRacingOrg private readonly IUnityContainer _container; public FormHorseRacing(IUnityContainer container) - { - InitializeComponent(); - _container = container ?? - throw new ArgumentNullException(nameof(container)); - } + { + InitializeComponent(); + _container = container ?? + throw new ArgumentNullException(nameof(container)); + } private void JockeysToolStripMenuItem_Click(object sender, EventArgs e) @@ -85,7 +85,44 @@ namespace ProjectHorseRacingOrg } } + private void DirectoryReportToolStripMenuItem_Click(object sender, EventArgs e) + { + try + { + _container.Resolve().ShowDialog(); + } + catch (Exception ex) + { + MessageBox.Show(ex.Message, " ", + MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } + private void RaceReportToolStripMenuItem_Click(object sender, EventArgs e) + { + try + { + _container.Resolve().ShowDialog(); + } + catch (Exception ex) + { + MessageBox.Show(ex.Message, " ", + MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } + + private void RaceDistributionToolStripMenuItem_Click(object sender, EventArgs e) + { + try + { + _container.Resolve().ShowDialog(); + } + catch (Exception ex) + { + MessageBox.Show(ex.Message, " ", + MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } } } diff --git a/ProjectHorseRacingOrg/Forms/FormRaceEntryReport.Designer.cs b/ProjectHorseRacingOrg/Forms/FormRaceEntryReport.Designer.cs new file mode 100644 index 0000000..4ea2fcd --- /dev/null +++ b/ProjectHorseRacingOrg/Forms/FormRaceEntryReport.Designer.cs @@ -0,0 +1,107 @@ +namespace ProjectHorseRacingOrg.Forms +{ + partial class FormRaceEntryReport + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + buttonCreate = new Button(); + buttonSelectFileName = new Button(); + labelData = new Label(); + labelFileName = new Label(); + dateTimePicker = new DateTimePicker(); + SuspendLayout(); + // + // buttonCreate + // + buttonCreate.Location = new Point(132, 155); + buttonCreate.Name = "buttonCreate"; + buttonCreate.Size = new Size(140, 29); + buttonCreate.TabIndex = 0; + buttonCreate.Text = "Сформировать"; + buttonCreate.UseVisualStyleBackColor = true; + buttonCreate.Click += ButtonCreate_Click; + // + // buttonSelectFileName + // + buttonSelectFileName.Location = new Point(39, 30); + buttonSelectFileName.Name = "buttonSelectFileName"; + buttonSelectFileName.Size = new Size(94, 29); + buttonSelectFileName.TabIndex = 1; + buttonSelectFileName.Text = "Выбрать"; + buttonSelectFileName.UseVisualStyleBackColor = true; + buttonSelectFileName.Click += ButtonSelectFileName_Click; + // + // labelData + // + labelData.AutoSize = true; + labelData.Location = new Point(39, 100); + labelData.Name = "labelData"; + labelData.Size = new Size(44, 20); + labelData.TabIndex = 2; + labelData.Text = "Дата:"; + // + // labelFileName + // + labelFileName.AutoSize = true; + labelFileName.Location = new Point(166, 34); + labelFileName.Name = "labelFileName"; + labelFileName.Size = new Size(45, 20); + labelFileName.TabIndex = 3; + labelFileName.Text = "Файл"; + // + // dateTimePicker + // + dateTimePicker.Location = new Point(100, 100); + dateTimePicker.Name = "dateTimePicker"; + dateTimePicker.Size = new Size(250, 27); + dateTimePicker.TabIndex = 4; + // + // FormRaceEntryReport + // + AutoScaleDimensions = new SizeF(8F, 20F); + AutoScaleMode = AutoScaleMode.Font; + ClientSize = new Size(402, 230); + Controls.Add(dateTimePicker); + Controls.Add(labelFileName); + Controls.Add(labelData); + Controls.Add(buttonSelectFileName); + Controls.Add(buttonCreate); + Name = "FormRaceEntryReport"; + Text = "FormRaceEntryReport"; + ResumeLayout(false); + PerformLayout(); + } + + #endregion + + private Button buttonCreate; + private Button buttonSelectFileName; + private Label labelData; + private Label labelFileName; + private DateTimePicker dateTimePicker; + } +} \ No newline at end of file diff --git a/ProjectHorseRacingOrg/Forms/FormRaceEntryReport.cs b/ProjectHorseRacingOrg/Forms/FormRaceEntryReport.cs new file mode 100644 index 0000000..5de42bf --- /dev/null +++ b/ProjectHorseRacingOrg/Forms/FormRaceEntryReport.cs @@ -0,0 +1,66 @@ +using ProjectHorseRacingOrg.Reports; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; +using Unity; + +namespace ProjectHorseRacingOrg.Forms; + +public partial class FormRaceEntryReport : Form +{ + private string _fileName = string.Empty; + private readonly IUnityContainer _container; + public FormRaceEntryReport(IUnityContainer container) + { + InitializeComponent(); + _container = container ?? + throw new ArgumentNullException(nameof(container)); + } + private void ButtonSelectFileName_Click(object sender, EventArgs e) + { + var sfd = new SaveFileDialog() + { + Filter = "Pdf Files | *.pdf" + }; + if (sfd.ShowDialog() == DialogResult.OK) + { + _fileName = sfd.FileName; + labelFileName.Text = Path.GetFileName(_fileName); + } + } + private void ButtonCreate_Click(object sender, EventArgs e) + { + try + { + if (string.IsNullOrWhiteSpace(_fileName)) + { + throw new Exception("Отсутствует имя файла для отчета"); + } + if + (_container.Resolve().CreateChart(_fileName, dateTimePicker.Value)) + { + MessageBox.Show("Документ сформирован", + "Формирование документа", + MessageBoxButtons.OK, + MessageBoxIcon.Information); + } + else + { + MessageBox.Show("Возникли ошибки при формировании документа.Подробности в логах", + "Формирование документа", + MessageBoxButtons.OK, MessageBoxIcon.Information); + } + } + catch (Exception ex) + { + MessageBox.Show(ex.Message, "Ошибка при создании очета", + MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } +} diff --git a/ProjectHorseRacingOrg/Forms/FormRaceEntryReport.resx b/ProjectHorseRacingOrg/Forms/FormRaceEntryReport.resx new file mode 100644 index 0000000..8b2ff64 --- /dev/null +++ b/ProjectHorseRacingOrg/Forms/FormRaceEntryReport.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/ProjectHorseRacingOrg/ProjectHorseRacingOrg.csproj b/ProjectHorseRacingOrg/ProjectHorseRacingOrg.csproj index b341f02..0a0e115 100644 --- a/ProjectHorseRacingOrg/ProjectHorseRacingOrg.csproj +++ b/ProjectHorseRacingOrg/ProjectHorseRacingOrg.csproj @@ -17,6 +17,7 @@ + diff --git a/ProjectHorseRacingOrg/Reports/ChartReport.cs b/ProjectHorseRacingOrg/Reports/ChartReport.cs new file mode 100644 index 0000000..3aa7d70 --- /dev/null +++ b/ProjectHorseRacingOrg/Reports/ChartReport.cs @@ -0,0 +1,53 @@ +using Microsoft.Extensions.Logging; +using ProjectHorseRacingOrg.Repositories; +using ProjectHorseRacingOrg.Repositories.Implementations; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ProjectHorseRacingOrg.Reports; + +public class ChartReport +{ + private readonly IRacingHorsesRepository _racingHorsesRepository; + private readonly ILogger _logger; + public ChartReport(IRacingHorsesRepository racingHorsesRepository, ILogger logger) + { + _racingHorsesRepository = racingHorsesRepository ?? + throw new ArgumentNullException(nameof(racingHorsesRepository)); + + _logger = logger ?? + throw new ArgumentNullException(nameof(logger)); + } + + public bool CreateChart(string filePath, DateTime dateTime) + { + try + { + new PdfBuilder(filePath) + .AddHeader("Участие лошадей") + .AddPieChart("Состоявшиеся соревнования", GetData(dateTime)) + .Build(); + return true; + } + catch (Exception ex) + { + _logger.LogError(ex, "Ошибка при формировании документа"); + return false; + } + } + private List<(string Caption, double Value)> GetData(DateTime dateTime) + { + return _racingHorsesRepository + .ReadRacingHorses() + .Where(x => x.RacingDate.Date == dateTime.Date) + .GroupBy(x => x.HorseId, (key, group) => new { + Id = key, + Count = group.Sum(x => x.Result) + }) + .Select(x => (x.Id.ToString(), (double)x.Count)) + .ToList(); + } +} diff --git a/ProjectHorseRacingOrg/Reports/PdfBuilder.cs b/ProjectHorseRacingOrg/Reports/PdfBuilder.cs new file mode 100644 index 0000000..1d4168c --- /dev/null +++ b/ProjectHorseRacingOrg/Reports/PdfBuilder.cs @@ -0,0 +1,88 @@ +using MigraDoc.DocumentObjectModel; +using MigraDoc.DocumentObjectModel.Shapes.Charts; +using MigraDoc.Rendering; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ProjectHorseRacingOrg.Reports; + +public class PdfBuilder +{ + private readonly string _filePath; + private readonly Document _document; + public PdfBuilder(string filePath) + { + if (string.IsNullOrWhiteSpace(filePath)) + { + throw new ArgumentNullException(nameof(filePath)); + } + if (File.Exists(filePath)) + { + File.Delete(filePath); + } + _filePath = filePath; + _document = new Document(); + DefineStyles(); + } + public PdfBuilder AddHeader(string header) + { + _document.AddSection().AddParagraph(header, "NormalBold"); + return this; + } + + public PdfBuilder AddPieChart(string title, List<(string Caption, double Value)> data) + { + if (data == null || data.Count == 0) + { + return this; + } + var chart = new Chart(ChartType.Pie2D); + var series = chart.SeriesCollection.AddSeries(); + series.Add(data.Select(x => x.Value).ToArray()); + + var xseries = chart.XValues.AddXSeries(); + xseries.Add(data.Select(x => x.Caption).ToArray()); + + chart.DataLabel.Type = DataLabelType.Percent; + chart.DataLabel.Position = DataLabelPosition.OutsideEnd; + + chart.Width = Unit.FromCentimeter(16); + chart.Height = Unit.FromCentimeter(12); + + chart.TopArea.AddParagraph(title); + + chart.XAxis.MajorTickMark = TickMarkType.Outside; + + chart.YAxis.MajorTickMark = TickMarkType.Outside; + chart.YAxis.HasMajorGridlines = true; + + chart.PlotArea.LineFormat.Width = 1; + chart.PlotArea.LineFormat.Visible = true; + + chart.TopArea.AddLegend(); + + _document.LastSection.Add(chart); + return this; + } + + public void Build() + { + Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); + var renderer = new PdfDocumentRenderer(true) + { + Document = _document + }; + renderer.RenderDocument(); + renderer.PdfDocument.Save(_filePath); + } + private void DefineStyles() + { + var headerStyle = _document.AddStyle("NormalBold", "Normal"); + headerStyle.Font.Bold = true; + headerStyle.Font.Size = 14; + headerStyle.Font.Color = Colors.DeepPink; + } +}