Преглед на файлове

Somewhat constructed job manufacutring summary dashboard

Kenric Nugteren преди 3 години
родител
ревизия
fb1f1e3a39

+ 105 - 0
prs.desktop/Dashboards/Manufacturing/JobManufacturingSummary.xaml

@@ -0,0 +1,105 @@
+<UserControl x:Class="PRSDesktop.Dashboards.Manufacturing.JobManufacturingSummary"
+             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
+             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
+             xmlns:local="clr-namespace:PRSDesktop.Dashboards.Manufacturing"
+             xmlns:prs="clr-namespace:Comal.Classes;assembly=PRSClasses"
+             xmlns:sf="http://schemas.syncfusion.com/wpf"
+             mc:Ignorable="d" 
+             d:DesignHeight="450" d:DesignWidth="800">
+    <UserControl.Resources>
+        <DataTemplate x:Key="JobHeaderTemplate">
+            <Border BorderBrush="Gray" BorderThickness="1" CornerRadius="3"
+                    Background="{Binding Color}"
+                    Width="150" Padding="5" Margin="2.5">
+                <Grid>
+                    <Grid.ColumnDefinitions>
+                        <ColumnDefinition Width="*"/>
+                    </Grid.ColumnDefinitions>
+                    <Grid.RowDefinitions>
+                        <RowDefinition Height="Auto"/>
+                    </Grid.RowDefinitions>
+
+                    <StackPanel Grid.Column="0">
+                        <TextBlock FontWeight="Bold" FontSize="11">
+                            <Run Text="{Binding Value.JobNumber}"/>
+                            <Run Text=": "/>
+                            <Run Text="{Binding Value.Name}"/>
+                        </TextBlock>
+                    </StackPanel>
+                </Grid>
+                <Border.ToolTip>
+                    <ToolTip>
+                        <StackPanel Grid.Column="0">
+                            <TextBlock FontWeight="Bold" FontSize="11"
+                                        HorizontalAlignment="Center">
+                            <Run Text="{Binding Value.JobNumber}"/>
+                            <Run Text=": "/>
+                            <Run Text="{Binding Value.Name}"/>
+                            </TextBlock>
+                        </StackPanel>
+                    </ToolTip>
+                </Border.ToolTip>
+            </Border>
+        </DataTemplate>
+        <DataTemplate x:Key="CardTemplate">
+            <Border BorderBrush="Gray" BorderThickness="1" CornerRadius="3"
+                    Background="White"
+                    Padding="5" Margin="2.5">
+                <Grid>
+                    <Grid.ColumnDefinitions>
+                        <ColumnDefinition Width="*"/>
+                    </Grid.ColumnDefinitions>
+                    <Grid.RowDefinitions>
+                        <RowDefinition Height="Auto"/>
+                    </Grid.RowDefinitions>
+
+                    <StackPanel Grid.Column="0">
+                        <TextBlock FontSize="11">
+                            <Run Text="Hours:"/>
+                            <Run Text="{Binding Path=Value.NHours, StringFormat={}{0:F2}}"/>
+                        </TextBlock>
+                        <TextBlock FontSize="11">
+                            <Run Text="No. Packets:"/>
+                            <Run Text="{Binding Value.NPackets}"/>
+                        </TextBlock>
+                    </StackPanel>
+                </Grid>
+                <Border.ToolTip>
+                    <ToolTip>
+                        <StackPanel Grid.Column="0">
+                            <TextBlock FontSize="11">
+                                <Run Text="Hours:"/>
+                                <Run Text="{Binding Value.NHours}"/>
+                            </TextBlock>
+                            <TextBlock FontSize="11">
+                                <Run Text="No. Packets:"/>
+                                <Run Text="{Binding Value.NPackets}"/>
+                            </TextBlock>
+                        </StackPanel>
+                    </ToolTip>
+                </Border.ToolTip>
+                <Border.Style>
+                    <Style TargetType="{x:Type Border}">
+                        <Style.Triggers>
+                            <DataTrigger Binding="{Binding Value.Empty}" Value="True">
+                                <Setter Property="Visibility" Value="Hidden"/>
+                            </DataTrigger>
+                        </Style.Triggers>
+                    </Style>
+                </Border.Style>
+            </Border>
+        </DataTemplate>
+    </UserControl.Resources>
+    
+    <Border BorderThickness="1" BorderBrush="Black" Background="White">
+        <sf:SfDataGrid x:Name="DataGrid"
+                       AutoGenerateColumns="True" AutoGeneratingColumn="DataGrid_AutoGeneratingColumn"
+                       QueryRowHeight="DataGrid_QueryRowHeight"
+                       FrozenColumnCount="1"
+                       AllowSorting="False">
+            
+        </sf:SfDataGrid>
+    </Border>
+</UserControl>

+ 269 - 0
prs.desktop/Dashboards/Manufacturing/JobManufacturingSummary.xaml.cs

@@ -0,0 +1,269 @@
+using Comal.Classes;
+using InABox.Clients;
+using InABox.Core;
+using javax.smartcardio;
+using PRSDesktop.WidgetGroups;
+using Syncfusion.UI.Xaml.Grid;
+using System;
+using System.Collections.Generic;
+using System.Data;
+using System.Linq;
+using System.Runtime.CompilerServices;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+using DataRow = System.Data.DataRow;
+
+namespace PRSDesktop.Dashboards.Manufacturing
+{
+    public class HeaderModel
+    {
+        public string Name { get; set; }
+
+        public HeaderModel(string name)
+        {
+            Name = name;
+        }
+    }
+    public class CardModel
+    {
+        private bool _empty;
+
+        public int NPackets { get; set; }
+        public double NHours { get; set; }
+        public bool Empty
+        {
+            get => _empty || NPackets == 0;
+            set => _empty = value;
+        }
+
+        public CardModel(int nPackets, int nHours)
+        {
+            NPackets = nPackets;
+            NHours = nHours;
+            Empty = false;
+        }
+
+        public CardModel()
+        {
+            NPackets = 0;
+            NHours = 0.0;
+            Empty = true;
+        }
+    }
+
+    public class JobManufacturingSummaryProperties : IDashboardProperties
+    {
+    }
+
+    public class JobManufacturingSummaryElement : DashboardElement<JobManufacturingSummary, WidgetGroups.Manufacturing, JobManufacturingSummaryProperties>
+    {
+    }
+
+    /// <summary>
+    /// Interaction logic for JobManufacturingSummary.xaml
+    /// </summary>
+    public partial class JobManufacturingSummary : UserControl, IDashboardWidget<WidgetGroups.Manufacturing, JobManufacturingSummaryProperties>
+    {
+        private class SectionColumn
+        {
+            public string ColumnName { get; set; }
+            public string DisplayName { get; set; }
+
+            public SolidColorBrush Background { get; set; }
+        }
+
+
+        private readonly Dictionary<Guid, SectionColumn> SectionColumns = new();
+        private List<Job> Jobs { get; set; } = new();
+        private List<ManufacturingFactory> Factories { get; set; } = new();
+        private Dictionary<Guid, List<ManufacturingSection>> Sections { get; set; } = new();
+        private List<FrameworkElement> Cards { get; set; } = new();
+        private DataTable Data { get; set; }
+
+        public JobManufacturingSummary()
+        {
+            InitializeComponent();
+        }
+
+        public JobManufacturingSummaryProperties Properties { get; set; }
+
+        public void Setup()
+        {
+            Jobs = new Client<Job>()
+                .Query(
+                    LookupFactory.DefineFilter<Job>(),
+                    new Columns<Job>(x => x.ID)
+                        .Add(x => x.JobNumber)
+                        .Add(x => x.Name)
+                        .Add(x => x.Color))
+                .ToList<Job>();
+
+            Factories = new Client<ManufacturingFactory>()
+                .Query(null, new Columns<ManufacturingFactory>(x => x.ID).Add(x => x.Name), new SortOrder<ManufacturingFactory>(x => x.Sequence))
+                .ToList<ManufacturingFactory>();
+
+            Sections = new Client<ManufacturingSection>()
+                .Query(
+                    new Filter<ManufacturingSection>(x => x.Hidden).IsEqualTo(false),
+                    new Columns<ManufacturingSection>(x => x.ID)
+                        .Add(x => x.Factory.ID)
+                        .Add(x => x.Name),
+                    new SortOrder<ManufacturingSection>(x => x.Sequence))
+                .ToObjects<ManufacturingSection>()
+                .GroupBy(x => x.Factory.ID).ToDictionary(x => x.Key, x => x.ToList());
+
+            SetupGrid();
+        }
+
+        private void SetupGrid()
+        {
+            DataGrid.HeaderTemplate = Resources["HeaderTemplate"] as DataTemplate;
+
+            Data = new DataTable();
+
+            Data.Columns.Add("Job", typeof(object));
+
+            var stackedHeaderRow = new StackedHeaderRow();
+            var factoryIdx = 0;
+            foreach (var factory in Factories)
+            {
+                if (!Sections.TryGetValue(factory.ID, out var sections)) continue;
+
+                foreach (var section in sections)
+                {
+                    var columnName = section.ID.ToString();
+                    SectionColumns.Add(section.ID, new SectionColumn
+                    {
+                        ColumnName = columnName,
+                        DisplayName = section.Name,
+                        Background = factoryIdx % 2 == 0 ? new SolidColorBrush(Colors.WhiteSmoke) : new SolidColorBrush(Colors.LightGray)
+                    });
+                    Data.Columns.Add(columnName, typeof(object));
+                }
+                stackedHeaderRow.StackedColumns.Add(new StackedColumn
+                {
+                    ChildColumns = string.Join(',', sections.Select(x => x.ID)),
+                    HeaderText = factory.Name
+                });
+                ++factoryIdx;
+            }
+            DataGrid.StackedHeaderRows.Add(stackedHeaderRow);
+        }
+
+        private void SetPosition(FrameworkElement element, int row, int rowSpan, int column, int columnSpan)
+        {
+            element.SetValue(Grid.RowProperty, row);
+            element.SetValue(Grid.RowSpanProperty, rowSpan);
+            element.SetValue(Grid.ColumnProperty, column);
+            element.SetValue(Grid.ColumnSpanProperty, columnSpan);
+        }
+
+        public void Refresh()
+        {
+            Data.Rows.Clear();
+
+            var packets = new Client<ManufacturingPacket>()
+                .Query(
+                    new Filter<ManufacturingPacket>(x => x.Archived).IsEqualTo(DateTime.MinValue)
+                        .And(x => x.Completed).IsEqualTo(DateTime.MinValue)
+                        .And(x => x.SetoutLink.JobLink.ID).InList(Jobs.Select(x => x.ID).ToArray()),
+                    new Columns<ManufacturingPacket>(x => x.ID)
+                        .Add(x => x.SetoutLink.JobLink.ID)
+                        .Add(x => x.StageLink.SectionID)
+                        .Add(x => x.TimeRemaining))
+                .ToObjects<ManufacturingPacket>()
+                .GroupBy(x => x.StageLink.SectionID)
+                .ToDictionary(
+                    x => x.Key,
+                    x => x.GroupBy(x => x.SetoutLink.JobLink.ID)
+                    .ToDictionary(x => x.Key, x => x.Aggregate(new CardModel(0, 0), (c, p) =>
+                    {
+                        c.NHours += p.TimeRemaining.TotalHours;
+                        ++c.NPackets;
+                        return c;
+                    })));
+
+            var rows = new Dictionary<Guid, DataRow>();
+            foreach (var job in Jobs)
+            {
+                var row = Data.NewRow();
+                Data.Rows.Add(row);
+                row["Job"] = job;
+                rows[job.ID] = row;
+            }
+
+            foreach (var (sectionID, column) in SectionColumns)
+            {
+                var sectionPackets = packets.GetValueOrDefault(sectionID);
+                foreach (var job in Jobs)
+                {
+                    if (!rows.TryGetValue(job.ID, out var row))
+                    {
+                        continue;
+                    }
+
+                    if (sectionPackets is null || !sectionPackets.TryGetValue(job.ID, out var model))
+                    {
+                        model = new CardModel();
+                    }
+                    row[column.ColumnName] = model;
+                }
+            }
+
+            DataGrid.ItemsSource = Data;
+        }
+
+        public void Shutdown()
+        {
+        }
+
+        private void DataGrid_AutoGeneratingColumn(object sender, Syncfusion.UI.Xaml.Grid.AutoGeneratingColumnArgs e)
+        {
+            if(Guid.TryParse(e.Column.MappingName, out var id))
+            {
+                var column = SectionColumns[id];
+                var style = new Style();
+                style.Setters.Add(new Setter(GridCell.BackgroundProperty, column.Background));
+
+                e.Column = new GridTemplateColumn
+                {
+                    HeaderText = column.DisplayName,
+                    CellStyle = style,
+                    MappingName = e.Column.MappingName,
+                    CellTemplate = Resources["CardTemplate"] as DataTemplate,
+                    SetCellBoundValue = true,
+                    ColumnSizer = GridLengthUnitType.Auto
+                };
+            }
+            else
+            {
+                e.Column = new GridTemplateColumn
+                {
+                    CellTemplate = Resources["JobHeaderTemplate"] as DataTemplate,
+                    HeaderText = e.Column.HeaderText,
+                    MappingName = e.Column.MappingName,
+                    SetCellBoundValue = true,
+                    ColumnSizer = GridLengthUnitType.Auto
+                };
+            }
+        }
+
+        private void DataGrid_QueryRowHeight(object sender, QueryRowHeightEventArgs e)
+        {
+            if(DataGrid.GridColumnSizer.GetAutoRowHeight(e.RowIndex, new GridRowSizingOptions(), out var height))
+            {
+                e.Height = height;
+                e.Handled = true;
+            }
+        }
+    }
+}