feat(vehicle): dedicated photo upload with MediaLibrary + form field
Vehicle model now implements HasMedia + InteractsWithMedia and
registers a 'photos' collection. VehicleResource form gets a
SpatieMediaLibraryFileUpload section (collapsible, max 6 photos,
imageEditor enabled).
Dashboard already checks vehicle->getFirstMediaUrl('photos') first
and falls back to the WO's photos, so uploading here immediately
populates the vehicle card on the dashboard without any view changes.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -93,6 +93,16 @@ class VehicleResource extends Resource
|
|||||||
Forms\Components\TextInput::make('mileage')->label(__('Kilometraj'))->numeric()->default(0),
|
Forms\Components\TextInput::make('mileage')->label(__('Kilometraj'))->numeric()->default(0),
|
||||||
Forms\Components\TextInput::make('color')->maxLength(40),
|
Forms\Components\TextInput::make('color')->maxLength(40),
|
||||||
]),
|
]),
|
||||||
|
Schemas\Components\Section::make(__('Foto'))
|
||||||
|
->collapsible()->collapsed()->compact()
|
||||||
|
->schema([
|
||||||
|
Forms\Components\SpatieMediaLibraryFileUpload::make('photos')
|
||||||
|
->label(__('Fotografii'))
|
||||||
|
->collection('photos')
|
||||||
|
->multiple()->reorderable()->image()->imageEditor()->maxFiles(6)
|
||||||
|
->helperText(__('Prima poză apare pe dashboard-ul fișei ca imagine principală a mașinii.'))
|
||||||
|
->columnSpanFull(),
|
||||||
|
]),
|
||||||
Forms\Components\Textarea::make('notes')->label(__('Notițe'))->columnSpanFull()->rows(3),
|
Forms\Components\Textarea::make('notes')->label(__('Notițe'))->columnSpanFull()->rows(3),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,10 +7,12 @@ use App\Models\Concerns\Auditable;
|
|||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
|
use Spatie\MediaLibrary\HasMedia;
|
||||||
|
use Spatie\MediaLibrary\InteractsWithMedia;
|
||||||
|
|
||||||
class Vehicle extends Model
|
class Vehicle extends Model implements HasMedia
|
||||||
{
|
{
|
||||||
use Auditable, BelongsToTenant, SoftDeletes;
|
use Auditable, BelongsToTenant, InteractsWithMedia, SoftDeletes;
|
||||||
|
|
||||||
public const BODY_TYPES = [
|
public const BODY_TYPES = [
|
||||||
'sedan' => 'Sedan', 'hatchback' => 'Hatchback', 'suv' => 'SUV',
|
'sedan' => 'Sedan', 'hatchback' => 'Hatchback', 'suv' => 'SUV',
|
||||||
@@ -44,4 +46,9 @@ class Vehicle extends Model
|
|||||||
{
|
{
|
||||||
return trim("{$this->make} {$this->model} " . ($this->year ?: ''));
|
return trim("{$this->make} {$this->model} " . ($this->year ?: ''));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function registerMediaCollections(): void
|
||||||
|
{
|
||||||
|
$this->addMediaCollection('photos');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1579,6 +1579,7 @@
|
|||||||
"Prețuri": "Prices",
|
"Prețuri": "Prices",
|
||||||
"Prețurile se înregistrează automat la fiecare recepție de PO.": "Prices are auto-recorded on every PO receipt.",
|
"Prețurile se înregistrează automat la fiecare recepție de PO.": "Prices are auto-recorded on every PO receipt.",
|
||||||
"Price": "Price",
|
"Price": "Price",
|
||||||
|
"Prima poză apare pe dashboard-ul fișei ca imagine principală a mașinii.": "The first photo appears on the work-order dashboard as the vehicle's main image.",
|
||||||
"Prima vizită": "First visit",
|
"Prima vizită": "First visit",
|
||||||
"Primește cereri din canalul Telegram + trimite confirmări automate.": "Receive requests from the Telegram channel + send auto-confirmations.",
|
"Primește cereri din canalul Telegram + trimite confirmări automate.": "Receive requests from the Telegram channel + send auto-confirmations.",
|
||||||
"Primit": "Incoming",
|
"Primit": "Incoming",
|
||||||
|
|||||||
@@ -1579,6 +1579,7 @@
|
|||||||
"Prețuri": "Цены",
|
"Prețuri": "Цены",
|
||||||
"Prețurile se înregistrează automat la fiecare recepție de PO.": "Цены регистрируются автоматически при каждой приёмке PO.",
|
"Prețurile se înregistrează automat la fiecare recepție de PO.": "Цены регистрируются автоматически при каждой приёмке PO.",
|
||||||
"Price": "Цена",
|
"Price": "Цена",
|
||||||
|
"Prima poză apare pe dashboard-ul fișei ca imagine principală a mașinii.": "Первое фото отображается на дашборде заказ-наряда как основное изображение автомобиля.",
|
||||||
"Prima vizită": "Первый визит",
|
"Prima vizită": "Первый визит",
|
||||||
"Primește cereri din canalul Telegram + trimite confirmări automate.": "Получайте заявки из Telegram-канала + отправляйте автоподтверждения.",
|
"Primește cereri din canalul Telegram + trimite confirmări automate.": "Получайте заявки из Telegram-канала + отправляйте автоподтверждения.",
|
||||||
"Primit": "Входящий",
|
"Primit": "Входящий",
|
||||||
|
|||||||
Reference in New Issue
Block a user