fix: update tour management

This commit is contained in:
2026-08-19 08:13:26 +03:30
parent c790091131
commit 852ea9d105
4 changed files with 564 additions and 153 deletions
+80 -33
View File
@@ -8,92 +8,139 @@ use Illuminate\Http\Request;
class TourController extends Controller
{
//لیست/آرشیو تورها با قابلیت فیلتر
/**
* لیست / آرشیو تورها با قابلیت فیلتر
*/
public function index(Request $request)
{
$query = Tour::query()
->where('status', 1) // فقط تورهای فعال
->with(['travelType', 'flights']); // بارگذاری زودهنگام برای جلوگیری از N+1
->where('status', 1)
->with(['travelType', 'flights']);
// فیلتر بر اساس نوع سفر (travel_type_id)
// فیلتر بر اساس نوع سفر
if ($request->filled('travel_type')) {
$query->where('travel_type_id', $request->input('travel_type'));
$query->where(
'travel_type_id',
$request->input('travel_type')
);
}
// فیلتر جستجوی متنی (عنوان)
// جستجو بر اساس عنوان
if ($request->filled('q')) {
$query->where('title', 'like', '%' . $request->input('q') . '%');
$query->where(
'title',
'like',
'%' . $request->input('q') . '%'
);
}
// فیلتر بازه قیمتی
// حداقل قیمت
if ($request->filled('price_min')) {
$query->where('price', '>=', $request->input('price_min'));
$query->where(
'price',
'>=',
$request->input('price_min')
);
}
// حداکثر قیمت
if ($request->filled('price_max')) {
$query->where('price', '<=', $request->input('price_max'));
$query->where(
'price',
'<=',
$request->input('price_max')
);
}
// مرتب‌سازی بر اساس قیمت (اگر خواستی)
// مرتب‌سازی
if ($request->filled('sort')) {
$query->orderBy('price', $request->input('sort') === 'desc' ? 'desc' : 'asc');
$query->orderBy(
'price',
$request->input('sort') === 'desc'
? 'desc'
: 'asc'
);
} else {
$query->latest(); // جدیدترین‌ها اول
$query->latest();
}
$tours = $query->paginate(12);
$travelTypes = TravelType::where('status', 1)->get(); // برای منوی فیلتر
// صفحه‌بندی
$tours = $query->paginate(12)->withQueryString();
return view('tours.index', compact('tours', 'travelTypes'));
// انواع سفر
$travelTypes = TravelType::where('status', 1)->get();
return view(
'tours.index',
compact('tours', 'travelTypes')
);
}
//حذف فیلترها و بازگشت به آرشیو کامل
/**
* حذف فیلترها
*/
public function removeFilters()
{
// ساده: فقط برگشت به آرشیو بدون هیچ پارامتری.
// (اگر از کوکی/سشن استفاده می‌کنی، اینجا آن‌ها را هم پاک کن)
return redirect()->route('tours.index');
}
//صفحه‌ی جزئیات یک تور
/**
* نمایش جزئیات یک تور
*/
public function show(Tour $tour)
{
// فقط اگر تور غیرفعال بود از دسترسی جلوگیری کن (مثلاً ریدایرکت)
if ($tour->status == 0) {
// فقط تورهای فعال قابل مشاهده باشند
if ($tour->status != 1) {
abort(404);
}
// بارگذاری پروازها + نوع سفر + نظرات تاییدشده
// افزایش تعداد بازدید
$tour->increment('views_count');
// بارگذاری اطلاعات مورد نیاز
$tour->load([
'flights',
'travelType',
// توجه: این رابطه را باید در مدل Tour تعریف کنی (morphMany)
'comments' => function ($q) {
$q->where('status', 1)->latest();
}
]);
// تورهای پیشنهادی مرتبط (هم‌دسته) برای نمایش کنار صفحه
// تورهای مرتبط
$relatedTours = Tour::where('status', 1)
->where('travel_type_id', $tour->travel_type_id)
->where('id', '!=', $tour->id)
->latest()
->limit(4)
->get();
return view('tours.show', compact('tour', 'relatedTours'));
return view(
'tours.show',
compact('tour', 'relatedTours')
);
}
//جستجوی پیشنهادی (Typeahead / AJAX) — خروجی JSON
/**
* جستجوی پیشنهادی
*/
public function searchSuggestion(Request $request)
{
$q = $request->input('q', '');
$tours = Tour::where('status', 1)
->where('title', 'like', '%' . $q . '%')
->where(
'title',
'like',
'%' . $q . '%'
)
->limit(8)
->get(['id', 'title', 'slug', 'price']);
->get([
'id',
'title',
'slug',
'price'
]);
return response()->json($tours);
}
}
+39 -39
View File
@@ -23,60 +23,60 @@ class TourStoreRequest extends FormRequest
public function rules(): array
{
return [
'travel_type_id' =>
[
'required',
'exists:travel_types,id'
],
// 'travel_type_id' =>
// [
// 'nullable',
// 'exists:travel_types,id'
// ],
'title' =>
[
'required',
'string',
'max:200'
],
'slug' =>
['required', 'string',
'max:200',
'regex:/^[a-z0-9-]+$/',
'unique:tours,slug,' . $this->tour
],
// 'slug' =>
// ['nullable', 'string',
// 'max:200',
// 'regex:/^[a-z0-9-]+$/',
// 'unique:tours,slug,' . $this->tour
// ],
'description' =>
[
'required',
'string'
],
'duration' =>
[
'required',
'string',
'max:50'
],
'start_date' =>
[
'required',
'date'
],
'end_date' =>
[
'required',
'date',
'after_or_equal:start_date'
],
// 'description' =>
// [
// 'nullable',
// 'string'
// ],
// 'duration' =>
// [
// 'nullable',
// 'string',
// 'max:50'
// ],
// 'start_date' =>
// [
// 'nullable',
// 'date'
// ],
// 'end_date' =>
// [
// 'nullable',
// 'date',
// 'after_or_equal:start_date'
// ],
'price' =>
[
'required',
'numeric',
'min:0'
],
'capacity' =>
[
'required',
'integer',
'min:0'],
// 'capacity' =>
// [
// 'nullable',
// 'integer',
// 'min:0'],
'images' =>
[
'required',
'nullable',
'array'
],
'images.*' =>