feat(ops): pending widget + manual status change + bulk complete + fix changeStatus placement

This commit is contained in:
Kazem Alghasi 2026-10-03 00:02:13 +03:30
parent 09b511808d
commit 537d3c70a9
3 changed files with 102 additions and 0 deletions

View File

@ -140,6 +140,24 @@ class ShipmentChecklistResource extends Resource
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\BulkAction::make('completeBulk')
->label('تکمیل گروهی')
->icon('heroicon-o-check-circle')
->color('success')
->requiresConfirmation()
->modalHeading('تکمیل آیتم‌های انتخاب‌شده')
->modalDescription('همه‌ی آیتم‌های انتخاب‌شده به‌عنوان تکمیل‌شده علامت‌گذاری می‌شوند.')
->action(function ($records) {
foreach ($records as $record) {
if (!$record->is_completed) {
$record->complete(auth()->id());
}
}
\Filament\Notifications\Notification::make()
->title('آیتم‌های انتخاب‌شده تکمیل شدند')
->success()
->send();
}),
Tables\Actions\DeleteBulkAction::make()
->visible(fn () => auth()->user()?->hasRole('super_admin')),
]),

View File

@ -627,6 +627,41 @@ class ShipmentResource extends Resource
->send();
}
}),
Tables\Actions\Action::make('changeStatus')
->label('تغییر وضعیت')
->icon('heroicon-o-arrow-path')
->color('warning')
->visible(fn () => auth()->user()?->hasAnyRole(['super_admin', 'admin', 'staff']))
->form([
Forms\Components\Select::make('new_status')
->label('وضعیت جدید')
->options(collect(\App\Enums\ShipmentStatus::cases())->mapWithKeys(fn ($s) => [$s->value => $s->label()]))
->required(),
Forms\Components\Textarea::make('reason')
->label('دلیل/توضیح')
->rows(2),
])
->action(function ($record, array $data) {
$oldStatus = $record->status;
$newStatus = \App\Enums\ShipmentStatus::from($data['new_status']);
$record->update(['status' => $newStatus]);
\App\Models\ShipmentStatusHistory::create([
'shipment_id' => $record->id,
'from_status' => $oldStatus->value,
'to_status' => $newStatus->value,
'reason' => $data['reason'] ?? 'تغییر دستی توسط ' . auth()->user()->name,
'changed_by' => auth()->id(),
]);
\Filament\Notifications\Notification::make()
->title('وضعیت سفارش تغییر کرد')
->body("از «{$oldStatus->label()}» به «{$newStatus->label()}»")
->success()
->send();
}),
])
->headerActions([
Action::make('exportCsv')
@ -727,4 +762,15 @@ class ShipmentResource extends Resource
'edit' => Pages\EditShipment::route('/{record}/edit'),
];
}
public static function getNavigationBadge(): ?string
{
$count = static::getModel()::where('status', \App\Enums\ShipmentStatus::PendingApproval)->count();
return $count > 0 ? (string) $count : null;
}
public static function getNavigationBadgeColor(): ?string
{
return 'warning';
}
}

View File

@ -0,0 +1,38 @@
<?php
namespace App\Filament\Widgets;
use App\Enums\ShipmentStatus;
use App\Models\Shipment;
use Filament\Widgets\StatsOverviewWidget as BaseWidget;
use Filament\Widgets\StatsOverviewWidget\Stat;
/**
* ویجت سفارش‌های در انتظار تأیید — مدیر را از سفارش‌های جدید مطلع می‌کند.
*/
class PendingOrdersWidget extends BaseWidget
{
protected static ?int $sort = 3;
protected static bool $isLazy = false;
protected int | string | array $columnSpan = 'full';
protected function getStats(): array
{
$pendingCount = Shipment::where('status', ShipmentStatus::PendingApproval)->count();
$approvedUnpaidCount = Shipment::where('status', ShipmentStatus::Approved)->count();
return [
Stat::make('در انتظار تأیید', $pendingCount)
->description($pendingCount > 0 ? 'سفارش جدید منتظر بررسی' : 'سفارش جدیدی نیست')
->descriptionIcon('heroicon-m-clock')
->color($pendingCount > 0 ? 'warning' : 'gray')
->url($pendingCount > 0 ? '/panel/shipments' : null),
Stat::make('در انتظار پرداخت', $approvedUnpaidCount)
->description('سفارش‌های تأییدشده — آماده پرداخت')
->descriptionIcon('heroicon-m-banknotes')
->color($approvedUnpaidCount > 0 ? 'info' : 'gray'),
];
}
}