fix : complete Activity log in admin side
This commit is contained in:
@@ -0,0 +1,23 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Admin;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Models\ActivityLog;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
class ActivityLogController extends Controller
|
||||||
|
{
|
||||||
|
public function index(Request $request)
|
||||||
|
{
|
||||||
|
$logs = ActivityLog::query()
|
||||||
|
->with('causer')
|
||||||
|
->when($request->filled('log_name'), function ($query) use ($request) {
|
||||||
|
$query->where('log_name', $request->input('log_name'));
|
||||||
|
})
|
||||||
|
->latest('created_at')
|
||||||
|
->paginate(20);
|
||||||
|
|
||||||
|
return view('admin.activity-logs.index', compact('logs'));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -169,7 +169,7 @@ class FlightController extends Controller
|
|||||||
$fileId = $uploadedFile->id;
|
$fileId = $uploadedFile->id;
|
||||||
}
|
}
|
||||||
|
|
||||||
Flight::create([
|
$flight = Flight::create([
|
||||||
'title' => $request->input('title'),
|
'title' => $request->input('title'),
|
||||||
'file_id' => $fileId,
|
'file_id' => $fileId,
|
||||||
'airline_id' => $request->input('airline_id'),
|
'airline_id' => $request->input('airline_id'),
|
||||||
@@ -183,8 +183,12 @@ class FlightController extends Controller
|
|||||||
'views' => 0,
|
'views' => 0,
|
||||||
'description' => $request->input('description'),
|
'description' => $request->input('description'),
|
||||||
'status' => $request->input('status'),
|
'status' => $request->input('status'),
|
||||||
|
'created_by' => auth('admin')->id(),
|
||||||
|
'updated_by' => auth('admin')->id(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
logActivity('flights', $flight->id, 'created');
|
||||||
|
|
||||||
DB::commit();
|
DB::commit();
|
||||||
|
|
||||||
} catch (\Exception $exception) {
|
} catch (\Exception $exception) {
|
||||||
@@ -227,6 +231,12 @@ class FlightController extends Controller
|
|||||||
|
|
||||||
public function update(Request $request, Flight $flight)
|
public function update(Request $request, Flight $flight)
|
||||||
{
|
{
|
||||||
|
$before = $flight->only([
|
||||||
|
'title', 'airline_id', 'flight_type', 'departure_time',
|
||||||
|
'departure_airport_id', 'arrival_airport_id', 'price',
|
||||||
|
'summary', 'capacity', 'description', 'status',
|
||||||
|
]);
|
||||||
|
|
||||||
$request->validate([
|
$request->validate([
|
||||||
'title' => [
|
'title' => [
|
||||||
'required',
|
'required',
|
||||||
@@ -327,6 +337,12 @@ class FlightController extends Controller
|
|||||||
'capacity' => $request->input('capacity'),
|
'capacity' => $request->input('capacity'),
|
||||||
'description' => $request->input('description'),
|
'description' => $request->input('description'),
|
||||||
'status' => $request->input('status'),
|
'status' => $request->input('status'),
|
||||||
|
'updated_by' => auth('admin')->id(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
logActivity('flights', $flight->id, 'updated', [
|
||||||
|
'before' => $before,
|
||||||
|
'after' => $flight->only(array_keys($before)),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
DB::commit();
|
DB::commit();
|
||||||
@@ -357,6 +373,7 @@ class FlightController extends Controller
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logActivity('flights', $flight->id, 'deleted');
|
||||||
$flight->delete();
|
$flight->delete();
|
||||||
|
|
||||||
return redirect()->route('admin.flights.index')->withErrors([
|
return redirect()->route('admin.flights.index')->withErrors([
|
||||||
|
|||||||
@@ -107,28 +107,24 @@ class TourController extends Controller
|
|||||||
$fileId = $uploadedFile->id;
|
$fileId = $uploadedFile->id;
|
||||||
}
|
}
|
||||||
|
|
||||||
Tour::create([
|
$tour = Tour::create([
|
||||||
'title' => $request->input('title'),
|
'title' => $request->input('title'),
|
||||||
|
|
||||||
'summary' => $request->input('summary'),
|
'summary' => $request->input('summary'),
|
||||||
|
|
||||||
'description' => $request->input('description'),
|
'description' => $request->input('description'),
|
||||||
|
|
||||||
'origin' => $request->input('origin'),
|
'origin' => $request->input('origin'),
|
||||||
|
|
||||||
'destination' => $request->input('destination'),
|
'destination' => $request->input('destination'),
|
||||||
|
|
||||||
'file_id' => $fileId,
|
'file_id' => $fileId,
|
||||||
|
|
||||||
'duration' => $request->input('duration'),
|
'duration' => $request->input('duration'),
|
||||||
|
|
||||||
'departure_time' => $request->input('departure_time'),
|
'departure_time' => $request->input('departure_time'),
|
||||||
|
|
||||||
'price' => $request->input('price'),
|
'price' => $request->input('price'),
|
||||||
|
|
||||||
'status' => $request->input('status'),
|
'status' => $request->input('status'),
|
||||||
|
'created_by' => auth('admin')->id(),
|
||||||
|
'updated_by' => auth('admin')->id(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
logActivity('tours', $tour->id, 'created');
|
||||||
|
|
||||||
|
|
||||||
DB::commit();
|
DB::commit();
|
||||||
|
|
||||||
} catch (\Exception $exception) {
|
} catch (\Exception $exception) {
|
||||||
@@ -160,9 +156,16 @@ class TourController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function update(tourUpdateRequest $request, Tour $tour) {
|
public function update(tourUpdateRequest $request, Tour $tour)
|
||||||
|
{
|
||||||
try {
|
try {
|
||||||
|
|
||||||
|
$before = $tour->only([
|
||||||
|
'title', 'summary', 'description', 'origin',
|
||||||
|
'destination', 'file_id', 'duration', 'price',
|
||||||
|
'departure_time', 'status',
|
||||||
|
]);
|
||||||
|
|
||||||
DB::beginTransaction();
|
DB::beginTransaction();
|
||||||
|
|
||||||
$fileId = $tour->file_id;
|
$fileId = $tour->file_id;
|
||||||
@@ -193,26 +196,21 @@ class TourController extends Controller
|
|||||||
|
|
||||||
$tour->update([
|
$tour->update([
|
||||||
'title' => $request->input('title'),
|
'title' => $request->input('title'),
|
||||||
|
|
||||||
'summary' => $request->input('summary'),
|
'summary' => $request->input('summary'),
|
||||||
|
|
||||||
'description' => $request->input('description'),
|
'description' => $request->input('description'),
|
||||||
|
|
||||||
'origin' => $request->input('origin'),
|
'origin' => $request->input('origin'),
|
||||||
|
|
||||||
'destination' => $request->input('destination'),
|
'destination' => $request->input('destination'),
|
||||||
|
|
||||||
'file_id' => $fileId,
|
'file_id' => $fileId,
|
||||||
|
|
||||||
'duration' => $request->input('duration'),
|
'duration' => $request->input('duration'),
|
||||||
|
|
||||||
'views' => 0,
|
|
||||||
|
|
||||||
'departure_time' => $request->input('departure_time'),
|
'departure_time' => $request->input('departure_time'),
|
||||||
|
|
||||||
'price' => $request->input('price'),
|
'price' => $request->input('price'),
|
||||||
|
|
||||||
'status' => $request->input('status'),
|
'status' => $request->input('status'),
|
||||||
|
'updated_by' => auth('admin')->id(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
logActivity('tours', $tour->id, 'updated', [
|
||||||
|
'before' => $before,
|
||||||
|
'after' => $tour->only(array_keys($before)),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
DB::commit();
|
DB::commit();
|
||||||
@@ -237,15 +235,16 @@ class TourController extends Controller
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function destroy(Tour $tour)
|
public function destroy(Tour $tour)
|
||||||
{
|
{
|
||||||
|
if ($tour->bookings()->exists()) {
|
||||||
|
return back()->withErrors(['error' => 'این پرواز دارای رزرو است و قابل حذف نیست.']);
|
||||||
|
}
|
||||||
|
|
||||||
|
logActivity('flights', $tour->id, 'deleted');
|
||||||
|
|
||||||
$tour->delete();
|
$tour->delete();
|
||||||
|
|
||||||
return redirect()
|
return redirect()->route('admin.flights.index')->withErrors(['success'=> 'پرواز با موفقیت حذف شد']);
|
||||||
->route('admin.tours.index')
|
|
||||||
->withErrors([
|
|
||||||
'success' => 'تور با موفقیت حذف شد'
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ class FlightController extends Controller
|
|||||||
|
|
||||||
public function show(Flight $flight)
|
public function show(Flight $flight)
|
||||||
{
|
{
|
||||||
abort_if($flight->status !== FlightStatus::ENABLE->value, 404);
|
abort_if($flight->status !== FlightStatus::ENABLE, 404);
|
||||||
|
|
||||||
$flight->increment('views');
|
$flight->increment('views');
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ class TourController extends Controller
|
|||||||
|
|
||||||
public function show(Tour $tour)
|
public function show(Tour $tour)
|
||||||
{
|
{
|
||||||
abort_if($tour->status !== TourStatus::ENABLE->value, 404);
|
abort_if($tour->status !== TourStatus::ENABLE, 404);
|
||||||
|
|
||||||
$tour->increment('views');
|
$tour->increment('views');
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class ActivityLog extends Model
|
||||||
|
{
|
||||||
|
public $timestamps = false;
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'log_name',
|
||||||
|
'subject_id',
|
||||||
|
'causer_id',
|
||||||
|
'event',
|
||||||
|
'changes',
|
||||||
|
];
|
||||||
|
|
||||||
|
protected $casts = [
|
||||||
|
'changes' => 'array',
|
||||||
|
'created_at' => 'datetime',
|
||||||
|
];
|
||||||
|
|
||||||
|
protected static function boot()
|
||||||
|
{
|
||||||
|
parent::boot();
|
||||||
|
|
||||||
|
static::creating(function ($log) {
|
||||||
|
$log->created_at = now();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function causer()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Admin::class, 'causer_id');
|
||||||
|
}
|
||||||
|
}
|
||||||
+3
-1
@@ -40,7 +40,9 @@ class File extends Model
|
|||||||
'extension',
|
'extension',
|
||||||
'size',
|
'size',
|
||||||
'original_name',
|
'original_name',
|
||||||
'path'
|
'path',
|
||||||
|
'created_by',
|
||||||
|
'updated_by'
|
||||||
];
|
];
|
||||||
|
|
||||||
public function flights()
|
public function flights()
|
||||||
|
|||||||
+20
-1
@@ -69,9 +69,15 @@ class Flight extends Model
|
|||||||
'capacity',
|
'capacity',
|
||||||
'description',
|
'description',
|
||||||
'views',
|
'views',
|
||||||
'status'
|
'status',
|
||||||
|
'created_by',
|
||||||
|
'updated_by',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
protected $hidden = [
|
||||||
|
'created_by',
|
||||||
|
'updated_by',
|
||||||
|
];
|
||||||
public function airline()
|
public function airline()
|
||||||
{
|
{
|
||||||
return $this->belongsTo(Airline::class);
|
return $this->belongsTo(Airline::class);
|
||||||
@@ -91,14 +97,17 @@ class Flight extends Model
|
|||||||
{
|
{
|
||||||
return $this->hasMany(Booking::class);
|
return $this->hasMany(Booking::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function arrivalAirport()
|
public function arrivalAirport()
|
||||||
{
|
{
|
||||||
return $this->belongsTo(Airport::class, 'arrival_airport_id');
|
return $this->belongsTo(Airport::class, 'arrival_airport_id');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function departureAirport()
|
public function departureAirport()
|
||||||
{
|
{
|
||||||
return $this->belongsTo(Airport::class, 'departure_airport_id');
|
return $this->belongsTo(Airport::class, 'departure_airport_id');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function comments()
|
public function comments()
|
||||||
{
|
{
|
||||||
return $this->hasMany(Comment::class, 'flight_id');
|
return $this->hasMany(Comment::class, 'flight_id');
|
||||||
@@ -113,4 +122,14 @@ class Flight extends Model
|
|||||||
$query->where('flight_type', $request->input('flight_type'));
|
$query->where('flight_type', $request->input('flight_type'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function creator()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Admin::class, 'created_by');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function updater()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Admin::class, 'updated_by');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,6 +35,8 @@ class Tour extends Model
|
|||||||
'departure_time',
|
'departure_time',
|
||||||
'status',
|
'status',
|
||||||
'created_at',
|
'created_at',
|
||||||
|
'created_by',
|
||||||
|
'updated_by',
|
||||||
];
|
];
|
||||||
|
|
||||||
public function file()
|
public function file()
|
||||||
@@ -51,4 +53,19 @@ class Tour extends Model
|
|||||||
{
|
{
|
||||||
return $this->hasMany(Comment::class, 'tour_id');
|
return $this->hasMany(Comment::class, 'tour_id');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected $hidden = [
|
||||||
|
'created_by',
|
||||||
|
'updated_by',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function creator()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Admin::class, 'created_by');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function updater()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Admin::class, 'updated_by');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
use App\Models\ActivityLog;
|
||||||
|
|
||||||
if (!function_exists('getUserFullName')) {
|
if (!function_exists('getUserFullName')) {
|
||||||
function getUserFullName(?\App\Models\User $user = null): string
|
function getUserFullName(?\App\Models\User $user = null): string
|
||||||
{
|
{
|
||||||
@@ -55,4 +58,17 @@ if (!function_exists('getFileUrl')) {
|
|||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (! function_exists('logActivity')) {
|
||||||
|
function logActivity(string $logName, int $subjectId, string $event, array $changes = []): void
|
||||||
|
{
|
||||||
|
ActivityLog::create([
|
||||||
|
'log_name' => $logName,
|
||||||
|
'subject_id' => $subjectId,
|
||||||
|
'causer_id' => auth('admin')->id(),
|
||||||
|
'event' => $event,
|
||||||
|
'changes' => $changes,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -139,7 +139,7 @@ return [
|
|||||||
|
|
|
|
||||||
| Redis is an open source, fast, and advanced key-value store that also
|
| Redis is an open source, fast, and advanced key-value store that also
|
||||||
| provides a richer body of commands than a typical key-value system
|
| provides a richer body of commands than a typical key-value system
|
||||||
| such as Memcached. You may define your connection settings here.
|
| such as Memcached. You may define your connection activity-logs here.
|
||||||
|
|
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -24828,7 +24828,7 @@ ul.files-main-nav li div.filemanager-upgrade-storage img {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* End:: mail-app */
|
/* End:: mail-app */
|
||||||
/* Start:: mail-settings */
|
/* Start:: mail-activity-logs */
|
||||||
.mail-notification-settings, .mail-security-settings {
|
.mail-notification-settings, .mail-security-settings {
|
||||||
width: 60%;
|
width: 60%;
|
||||||
}
|
}
|
||||||
@@ -24896,7 +24896,7 @@ ul.files-main-nav li div.filemanager-upgrade-storage img {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* End:: mail-settings */
|
/* End:: mail-activity-logs */
|
||||||
/* Start:: task */
|
/* Start:: task */
|
||||||
/* Start::task-kanboard-board */
|
/* Start::task-kanboard-board */
|
||||||
.Meno-kanban-board {
|
.Meno-kanban-board {
|
||||||
|
|||||||
@@ -1,3 +1,107 @@
|
|||||||
@extends('admin.layouts.app')
|
@extends('admin.layouts.app')
|
||||||
@section('breadcrumb')<div><h1 class="page-title fw-medium fs-18 mb-1">لاگ تغییرات</h1><span class="text-muted fs-12">ثبت چه کسی، چه زمانی و چه تغییری روی اطلاعات پرواز و تور</span></div>@endsection
|
|
||||||
@section('content')<div class="container-fluid pt-4"><div class="card custom-card"><div class="card-body"><form method="GET"><div class="row g-2"><div class="col-md-4"><input class="form-control" name="search" value="{{ request('search') }}" placeholder="جستجو در توضیحات"></div><div class="col-md-3"><select class="form-control" name="subject_type"><option value="">همه بخشها</option><option value="flight" @selected(request('subject_type')==='flight')>پرواز</option><option value="tour" @selected(request('subject_type')==='tour')>تور</option></select></div><div class="col-md-2"><button class="btn btn-light w-100">جستجو</button></div></div></form></div></div><div class="card custom-card mt-3"><div class="table-responsive"><table class="table text-nowrap"><thead><tr><th>مدیر</th><th>بخش</th><th>عملیات</th><th>شرح تغییر</th><th>تاریخ</th></tr></thead><tbody>@forelse(($logs ?? []) as $log)<tr><td>{{ $log->admin->first_name ?? '-' }} {{ $log->admin->last_name ?? '' }}</td><td>{{ $log->subject_type ?? '-' }}</td><td>{{ $log->action ?? '-' }}</td><td>{{ $log->description ?? '-' }}</td><td>{{ isset($log->created_at) ? $log->created_at->toJalali()->format('Y/m/d H:i') : '-' }}</td></tr>@empty<tr><td colspan="5" class="text-center text-muted py-5">لاگی برای نمایش وجود ندارد.</td></tr>@endforelse</tbody></table></div></div>{{ ($logs ?? collect())->links() }}</div>@endsection
|
@section('content')
|
||||||
|
<div class="container-fluid pt-4">
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xl-12">
|
||||||
|
|
||||||
|
<div class="card custom-card">
|
||||||
|
|
||||||
|
<div class="card-header">
|
||||||
|
<div class="card-title">
|
||||||
|
لاگ تغییرات پرواز و تور
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card-body pt-0">
|
||||||
|
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table text-nowrap">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>کاربر</th>
|
||||||
|
<th>عملیات</th>
|
||||||
|
<th>مربوط به</th>
|
||||||
|
<th>تغییرات</th>
|
||||||
|
<th>زمان</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
@forelse($logs as $log)
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
{{ optional($log->causer)->first_name ?? 'نامشخص' }}
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
@switch($log->event)
|
||||||
|
@case('created')
|
||||||
|
<span class="badge bg-success-transparent">ایجاد</span>
|
||||||
|
@break
|
||||||
|
|
||||||
|
@case('updated')
|
||||||
|
<span class="badge bg-warning-transparent">ویرایش</span>
|
||||||
|
@break
|
||||||
|
|
||||||
|
@case('deleted')
|
||||||
|
<span class="badge bg-danger-transparent">حذف</span>
|
||||||
|
@break
|
||||||
|
|
||||||
|
@default
|
||||||
|
{{ $log->event }}
|
||||||
|
@endswitch
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
{{ $log->log_name === 'flights' ? 'پرواز' : 'تور' }}
|
||||||
|
#{{ $log->subject_id }}
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
@if($log->event === 'updated' && $log->changes)
|
||||||
|
<ul class="mb-0 ps-3">
|
||||||
|
@foreach($log->changes['after'] as $field => $newValue)
|
||||||
|
@if(($log->changes['before'][$field] ?? null) != $newValue)
|
||||||
|
<li>
|
||||||
|
{{ $field }}:
|
||||||
|
«{{ $log->changes['before'][$field] ?? '—' }}»
|
||||||
|
←
|
||||||
|
«{{ $newValue }}»
|
||||||
|
</li>
|
||||||
|
@endif
|
||||||
|
@endforeach
|
||||||
|
</ul>
|
||||||
|
@elseif($log->event === 'created')
|
||||||
|
ایجاد رکورد جدید
|
||||||
|
@else
|
||||||
|
حذف رکورد
|
||||||
|
@endif
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
{{ verta($log->created_at)->format('Y/m/d H:i') }}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
@empty
|
||||||
|
<tr>
|
||||||
|
<td colspan="5" class="text-center">
|
||||||
|
لاگی ثبت نشده است
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
@endforelse
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{ $logs->links() }}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
@endsection
|
||||||
|
|||||||
@@ -1,141 +0,0 @@
|
|||||||
@extends('admin.layouts.app')
|
|
||||||
|
|
||||||
@section('content')
|
|
||||||
<div class="main-content app-content">
|
|
||||||
<div class="container-fluid pt-4">
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-xl-12">
|
|
||||||
<form action="{{ route('admin.product.store') }}" method="POST" enctype="multipart/form-data">
|
|
||||||
@csrf
|
|
||||||
@error('general')
|
|
||||||
<span class="text-danger">{{ $message }}</span>
|
|
||||||
@enderror
|
|
||||||
<div class="card custom-card">
|
|
||||||
<div class="card-header">
|
|
||||||
<div class="card-title">
|
|
||||||
ایجاد محصول
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="card-body pt-0">
|
|
||||||
|
|
||||||
|
|
||||||
<div class="row gy-3">
|
|
||||||
<!-- Name -->
|
|
||||||
<div class="col-xl-6">
|
|
||||||
<label class="form-label">نام فارسی</label>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
class="form-control" name="name"
|
|
||||||
placeholder="نام فارسی را وارد کنید"
|
|
||||||
value="{{ old('name') }}"
|
|
||||||
/>
|
|
||||||
@error('name')
|
|
||||||
<span class="text-danger">{{ $message }}</span>
|
|
||||||
@enderror
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Name -->
|
|
||||||
<div class="col-xl-6">
|
|
||||||
<label class="form-label">نام انگلیسی</label>
|
|
||||||
<input type="text" class="form-control" name="en_name"
|
|
||||||
placeholder="نام انگلیسی را وارد کنید" value="{{ old('en_name') }}">
|
|
||||||
@error('en_name')
|
|
||||||
<span class="text-danger">{{ $message }}</span>
|
|
||||||
@enderror
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Category -->
|
|
||||||
<div class="col-xl-6">
|
|
||||||
<label class="form-label">دسته بندی</label>
|
|
||||||
<select class="form-control" name="category_id">
|
|
||||||
<option>یک دسته بندی انتخاب کنید</option>
|
|
||||||
@foreach($productCategories as $productCategory)
|
|
||||||
<option value="{{ $productCategory->id }}" >
|
|
||||||
{{ $productCategory->name }}
|
|
||||||
</option>
|
|
||||||
@endforeach
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Price -->
|
|
||||||
<div class="col-xl-6">
|
|
||||||
<label class="form-label">قیمت</label>
|
|
||||||
<input type="number" class="form-control" name="price"
|
|
||||||
placeholder="قیمت را وارد کنید" value="{{old('price')}}">
|
|
||||||
@error('price')
|
|
||||||
<span class="text-danger">{{ $message }}</span>
|
|
||||||
@enderror
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Discount Price -->
|
|
||||||
<div class="col-xl-6">
|
|
||||||
<label class="form-label">تخفیف</label>
|
|
||||||
<input type="number" class="form-control" name="discount"
|
|
||||||
placeholder="تخفیف را وارد کنید"
|
|
||||||
value="{{ old('discount') }}">
|
|
||||||
@error('discount')
|
|
||||||
<span class="text-danger">{{ $message }}</span>
|
|
||||||
@enderror
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Stock -->
|
|
||||||
<div class="col-xl-6">
|
|
||||||
<label class="form-label">موجودی</label>
|
|
||||||
<input type="number" class="form-control" name="qty"
|
|
||||||
placeholder="تعداد موجودی را وارد کنید" value="{{ old('qty') }}">
|
|
||||||
@error('qty')
|
|
||||||
<span class="text-danger">{{ $message }}</span>
|
|
||||||
@enderror
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Description -->
|
|
||||||
<div class="col-xl-12">
|
|
||||||
<label class="form-label">توضیحات</label>
|
|
||||||
<textarea class="form-control" name="description" rows="4"
|
|
||||||
placeholder="توضیحات را وارد کنید">{{ old('description') }}</textarea>
|
|
||||||
@error('description')
|
|
||||||
<span class="text-danger">{{ $message }}</span>
|
|
||||||
@enderror
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Product Images -->
|
|
||||||
<div
|
|
||||||
class="image-upload-wrapper d-flex flex-wrap gap-2 px-0 pt-0 mt-3"
|
|
||||||
id="imagePreviewContainer"
|
|
||||||
style=" border-radius: 8px; padding: 10px;"
|
|
||||||
>
|
|
||||||
<label
|
|
||||||
id="uploadPlaceholder"
|
|
||||||
class="upload-placeholder"
|
|
||||||
for="imageInput"
|
|
||||||
style="cursor: pointer; width:150px; height:150px; display: flex; justify-content: center; align-items: center; border: 2px dashed #ccc; border-radius: 8px; padding: 20px; text-align: center;"
|
|
||||||
>
|
|
||||||
<div>📷<br><strong>آپلود یا کشیدن</strong></div>
|
|
||||||
<small style="color:#999;">JPG / PNG / JPEG / WEBP</small>
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
id="imageInput"
|
|
||||||
name="images[]"
|
|
||||||
type="file"
|
|
||||||
accept=".jpg,.png,.jpeg,.webp"
|
|
||||||
multiple
|
|
||||||
style="display:none"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="card-footer text-end">
|
|
||||||
<button type="submit" class="btn btn-primary">ایجاد محصول</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@endsection
|
|
||||||
Reference in New Issue
Block a user