added production line count chart
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace App\Filament\Pages;
|
namespace App\Filament\Pages;
|
||||||
|
|
||||||
|
use App\Filament\Widgets\CumulativeChart;
|
||||||
use Filament\Forms\Components\Select;
|
use Filament\Forms\Components\Select;
|
||||||
use Filament\Forms\Components\TextInput;
|
use Filament\Forms\Components\TextInput;
|
||||||
use Filament\Forms\Form;
|
use Filament\Forms\Form;
|
||||||
@@ -8,49 +9,51 @@ use Filament\Pages\Dashboard\Concerns\HasFiltersForm;
|
|||||||
use Filament\Tables\Filters\SelectFilter;
|
use Filament\Tables\Filters\SelectFilter;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
use App\Models\Plant;
|
use App\Models\Plant;
|
||||||
|
use Filament\Widgets\Widget;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
|
||||||
class Dashboard extends \Filament\Pages\Dashboard
|
class Dashboard extends \Filament\Pages\Dashboard
|
||||||
{
|
{
|
||||||
use HasFiltersForm;
|
use HasFiltersForm;
|
||||||
|
|
||||||
public function filtersForm(Form $form): Form
|
protected static ?string $navigationGroup = 'Production DashBoard';
|
||||||
{
|
|
||||||
$selectedPlant = session('selected_plant', request()->input('filters.Plant'));
|
|
||||||
return $form->schema([
|
|
||||||
// Plant Filter
|
|
||||||
Select::make('Plant')
|
|
||||||
->options(Plant::pluck('name', 'id')) // Fetch plant names with their IDs
|
|
||||||
->label('Select Plant')
|
|
||||||
->reactive()
|
|
||||||
->afterStateUpdated(function ($state, callable $set) use ($selectedPlant) {
|
|
||||||
session(['selected_plant' => $state]);
|
|
||||||
session()->forget('selected_line');
|
|
||||||
$set('Plant', $state);
|
|
||||||
$set('Line', null);
|
|
||||||
$this->triggerChartUpdate();
|
|
||||||
}),
|
|
||||||
|
|
||||||
// Line Filter
|
|
||||||
Select::make('Line')
|
public function mount(): void
|
||||||
->options(function ($get) {
|
{
|
||||||
$plantId = $get('Plant');
|
$this->filtersForm->fill([
|
||||||
return $plantId ? Plant::find($plantId)->getLineNames()->pluck('name', 'id') : [];
|
'plant' => Plant::first()?->id // Default to first plant
|
||||||
})
|
|
||||||
->label('Select Line')
|
|
||||||
->reactive()
|
|
||||||
->afterStateUpdated(function ($state) {
|
|
||||||
session(['selected_line' => $state]); // Store in session
|
|
||||||
$this->triggerChartUpdate(); // Notify chart to refresh
|
|
||||||
}),
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper to check if both filters are set
|
public function filtersForm(Form $form): Form
|
||||||
public function triggerChartUpdate(): void
|
|
||||||
{
|
{
|
||||||
if (session()->has('selected_plant') && session()->has('selected_line')) {
|
return $form
|
||||||
$this->dispatch('filtersUpdated');
|
->statePath('filters') // Store form state in 'filters'
|
||||||
|
->schema([
|
||||||
|
Select::make('plant')
|
||||||
|
->options(Plant::pluck('name', 'id'))
|
||||||
|
->label('Select Plant')
|
||||||
|
->reactive()
|
||||||
|
->afterStateUpdated(function ($state) {
|
||||||
|
session(['selected_plant' => $state]); // fixed typo
|
||||||
|
$this->dispatch('cumulativeChart'); // custom Livewire event
|
||||||
|
}),
|
||||||
|
]);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static function getNavigationLabel(): string
|
||||||
|
{
|
||||||
|
return 'Production Line Count';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getHeading(): string
|
||||||
|
{
|
||||||
|
return 'Production Line Count';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
78
app/Filament/Pages/HourlyProduction.php
Normal file
78
app/Filament/Pages/HourlyProduction.php
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Filament\Pages;
|
||||||
|
|
||||||
|
use App\Models\Plant;
|
||||||
|
use Filament\Forms\Components\Select;
|
||||||
|
use Filament\Forms\Form;
|
||||||
|
use Filament\Pages\Dashboard\Concerns\HasFiltersForm;
|
||||||
|
use Filament\Pages\Page;
|
||||||
|
use Filament\Tables\Concerns\HasFilters;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
|
||||||
|
class HourlyProduction extends Page
|
||||||
|
{
|
||||||
|
protected static ?string $navigationIcon = 'heroicon-o-document-text';
|
||||||
|
|
||||||
|
protected static string $view = 'filament.pages.hourly-production';
|
||||||
|
|
||||||
|
protected static ?string $navigationGroup = 'Production DashBoard';
|
||||||
|
|
||||||
|
use HasFiltersForm;
|
||||||
|
|
||||||
|
|
||||||
|
public function mount(): void
|
||||||
|
{
|
||||||
|
$this->filtersForm->fill([
|
||||||
|
'plant' => Plant::first()?->id // Default to first plant
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function filtersForm(Form $form): Form
|
||||||
|
{
|
||||||
|
return $form
|
||||||
|
->statePath('filters')
|
||||||
|
->schema([
|
||||||
|
|
||||||
|
Select::make('plant')
|
||||||
|
->options(Plant::pluck('name', 'id'))
|
||||||
|
->label('Select Plant')
|
||||||
|
->reactive()
|
||||||
|
->afterStateUpdated(function ($state) {
|
||||||
|
session(['selected_plant' => $state]);
|
||||||
|
$this->triggerChartUpdate();
|
||||||
|
}),
|
||||||
|
|
||||||
|
// Line Filter
|
||||||
|
Select::make('line')
|
||||||
|
->options(function ($get) {
|
||||||
|
$plantId = $get('plant');
|
||||||
|
return $plantId ? Plant::find($plantId)->getLineNames()->pluck('name', 'id') : [];
|
||||||
|
})
|
||||||
|
->label('Select Line')
|
||||||
|
->reactive()
|
||||||
|
->afterStateUpdated(function ($state) {
|
||||||
|
session(['selected_line' => $state]);
|
||||||
|
$this->triggerChartUpdate();
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
->columns(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function triggerChartUpdate(): void
|
||||||
|
{
|
||||||
|
if (session()->has('selected_plant') && session()->has('selected_line')) {
|
||||||
|
$this->dispatch('filtersUpdated');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getNavigationLabel(): string
|
||||||
|
{
|
||||||
|
return 'Hourly Production Count';
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function canAccess(): bool
|
||||||
|
{
|
||||||
|
return Auth::check() && Auth::user()->can('view production dashboard');
|
||||||
|
}
|
||||||
|
}
|
||||||
111
app/Filament/Widgets/CumulativeChart.php
Normal file
111
app/Filament/Widgets/CumulativeChart.php
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Filament\Widgets;
|
||||||
|
|
||||||
|
use App\Models\Line;
|
||||||
|
use Filament\Widgets\ChartWidget;
|
||||||
|
|
||||||
|
class CumulativeChart extends ChartWidget
|
||||||
|
{
|
||||||
|
protected static ?string $heading = 'Production Line Count';
|
||||||
|
|
||||||
|
protected $listeners = ['cumulativeChart'];
|
||||||
|
|
||||||
|
|
||||||
|
protected int|string|array $columnSpan = 12;
|
||||||
|
protected function getData(): array
|
||||||
|
{
|
||||||
|
$selectedPlant = session('selected_plant') ?? session('select_plant');
|
||||||
|
$activeFilter = $this->filter;
|
||||||
|
|
||||||
|
// Define date range based on filter
|
||||||
|
switch ($activeFilter) {
|
||||||
|
case 'yesterday':
|
||||||
|
$startDate = now()->subDay()->startOfDay();
|
||||||
|
$endDate = now()->subDay()->endOfDay();
|
||||||
|
break;
|
||||||
|
case 'this_week':
|
||||||
|
$startDate = now()->startOfWeek();
|
||||||
|
$endDate = now()->endOfWeek();
|
||||||
|
break;
|
||||||
|
case 'this_month':
|
||||||
|
$startDate = now()->startOfMonth();
|
||||||
|
$endDate = now()->endOfMonth();
|
||||||
|
break;
|
||||||
|
default: // today
|
||||||
|
$startDate = now()->startOfDay();
|
||||||
|
$endDate = now()->endOfDay();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get all lines for selected plant
|
||||||
|
$lines = Line::where('plant_id', $selectedPlant)
|
||||||
|
->pluck('name', 'id')
|
||||||
|
->toArray();
|
||||||
|
|
||||||
|
// Get total production per line in the date range
|
||||||
|
$production = \DB::table('production_quantities')
|
||||||
|
->select('line_id', \DB::raw('COUNT(*) as total_quantity'))
|
||||||
|
->whereBetween('created_at', [$startDate, $endDate])
|
||||||
|
->whereIn('line_id', array_keys($lines))
|
||||||
|
->groupBy('line_id')
|
||||||
|
->pluck('total_quantity', 'line_id')
|
||||||
|
->toArray();
|
||||||
|
|
||||||
|
// Match quantities with lines (fill 0 if missing)
|
||||||
|
$labels = [];
|
||||||
|
$data = [];
|
||||||
|
|
||||||
|
foreach ($lines as $lineId => $lineName) {
|
||||||
|
$labels[] = $lineName;
|
||||||
|
$data[] = $production[$lineId] ?? 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
'labels' => $labels,
|
||||||
|
'datasets' => [
|
||||||
|
[
|
||||||
|
'label' => match ($activeFilter) {
|
||||||
|
'yesterday' => "Production Quantity (Yesterday)",
|
||||||
|
'this_week' => "Weekly Production This Month",
|
||||||
|
'this_month' => "Yesterday's Hourly Production",
|
||||||
|
default => "Today's Production",
|
||||||
|
},
|
||||||
|
'data' => $data,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected function getType(): string
|
||||||
|
{
|
||||||
|
return 'bar';
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getFilters(): ?array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'today' => 'Today',
|
||||||
|
'yesterday' => 'Yesterday',
|
||||||
|
'this_week'=> 'This Week',
|
||||||
|
'this_month'=> 'This Month',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getOptions(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'scales' => [
|
||||||
|
'y' => [
|
||||||
|
'beginAtZero' => true, //Start Y-axis from 0
|
||||||
|
'ticks' => [
|
||||||
|
'stepSize' => 0.5,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -8,8 +8,7 @@ class ItemOverview extends ChartWidget
|
|||||||
{
|
{
|
||||||
protected static ?string $heading = 'Hourly Production';
|
protected static ?string $heading = 'Hourly Production';
|
||||||
|
|
||||||
// protected int|string|array $columnSpan = 'full';
|
protected int|string|array $columnSpan = '12';
|
||||||
protected int|string|array $columnSpan = 12;
|
|
||||||
|
|
||||||
protected static ?string $maxHeight = '350px';
|
protected static ?string $maxHeight = '350px';
|
||||||
|
|
||||||
@@ -146,20 +145,6 @@ class ItemOverview extends ChartWidget
|
|||||||
return 'line';
|
return 'line';
|
||||||
}
|
}
|
||||||
|
|
||||||
// protected function getContent(): string
|
|
||||||
// {
|
|
||||||
// return '<div style="height: 100%;">' . $this->chart->render() . '</div>';
|
|
||||||
// }
|
|
||||||
// protected function getContent(): string
|
|
||||||
// {
|
|
||||||
// return <<<HTML
|
|
||||||
// <div id="chart-container" style="height: 100vh; width: 100%;">
|
|
||||||
// {$this->chart->render()}
|
|
||||||
// </div>
|
|
||||||
// HTML;
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
protected function getOptions(): array
|
protected function getOptions(): array
|
||||||
{
|
{
|
||||||
@@ -173,15 +158,6 @@ class ItemOverview extends ChartWidget
|
|||||||
],
|
],
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
|
||||||
// 'scales' => [
|
|
||||||
// 'y' => [
|
|
||||||
// 'beginAtZero' => true, //Start Y-axis from 0
|
|
||||||
// 'ticks' => [
|
|
||||||
// 'stepSize' => 0.5,
|
|
||||||
// ],
|
|
||||||
// ],
|
|
||||||
// ],
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -194,4 +170,10 @@ class ItemOverview extends ChartWidget
|
|||||||
'this_month'=> 'This Month',
|
'this_month'=> 'This Month',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function canView(): bool
|
||||||
|
{
|
||||||
|
// Only show on HourlyProduction page
|
||||||
|
return request()->routeIs('filament.pages.hourly-production');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
<x-filament-panels::page>
|
||||||
|
<div class="space-y-4">
|
||||||
|
{{-- Filters form --}}
|
||||||
|
{{ $this->filtersForm($this->form) }}
|
||||||
|
|
||||||
|
{{-- Chart Widget --}}
|
||||||
|
@livewire(\App\Filament\Widgets\ItemOverview::class)
|
||||||
|
</div>
|
||||||
|
</x-filament-panels::page>
|
||||||
Reference in New Issue
Block a user