feat(Category): add category

This commit is contained in:
2026-05-03 23:38:21 +03:30
parent ededb41a3a
commit 21b060c527
13 changed files with 300 additions and 5 deletions

View File

@@ -0,0 +1,89 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use App\Models\JudicialPrecedentCategory;
use Illuminate\Http\Request;
class JudicialPrecedentCategoryController extends Controller
{
/**
* Display a listing of the resource.
*/
public function index(Request $request)
{
$query = JudicialPrecedentCategory::query();
if ($request->filled('q')) {
$q = $request->q;
$query->where('name', 'like', "%{$q}%");
}
$perPage = min(max((int) $request->input('per_page', 15), 10), 100);
$categories = $query->paginate($perPage)->withQueryString();
return view('admin.judicial-precedent-category.index', compact('categories'));
}
/**
* Show the form for creating a new resource.
*/
public function create()
{
return view('admin.judicial-precedent-category.create');
}
/**
* Store a newly created resource in storage.
*/
public function store(Request $request)
{
$validated = $request->validate([
'name' => 'required|string|unique:judicial_precedent_categories,name'
]);
JudicialPrecedentCategory::create($validated);
return redirect(route('judicial-precedent-category.index'));
}
/**
* Display the specified resource.
*/
public function show(string $id)
{
//
}
/**
* Show the form for editing the specified resource.
*/
public function edit(JudicialPrecedentCategory $judicialPrecedentCategory)
{
return view('admin.judicial-precedent-category.update', compact('judicialPrecedentCategory'));
}
/**
* Update the specified resource in storage.
*/
public function update(Request $request, JudicialPrecedentCategory $judicialPrecedentCategory)
{
$validated = $request->validate([
'name' => 'required|string|unique:judicial_precedent_categories,name,' . $judicialPrecedentCategory->id
]);
$judicialPrecedentCategory->update($validated);
return redirect(route('judicial-precedent-category.edit', $judicialPrecedentCategory->id));
}
/**
* Remove the specified resource from storage.
*/
public function destroy(JudicialPrecedentCategory $judicialPrecedentCategory)
{
$judicialPrecedentCategory->delete();
return redirect(route('judicial-precedent-category.index'));
}
}

View File

@@ -5,6 +5,7 @@ namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Models\Art; use App\Models\Art;
use App\Models\JudicialPrecedent; use App\Models\JudicialPrecedent;
use App\Models\JudicialPrecedentCategory;
use Illuminate\Http\Request; use Illuminate\Http\Request;
class JudicialPrecedentController extends Controller class JudicialPrecedentController extends Controller
@@ -31,7 +32,8 @@ class JudicialPrecedentController extends Controller
public function create() public function create()
{ {
$arts = Art::all(); $arts = Art::all();
return view('admin.judicial-precedent.create', compact('arts')); $categories = JudicialPrecedentCategory::all();
return view('admin.judicial-precedent.create', compact('arts', 'categories'));
} }
public function store(Request $request) public function store(Request $request)
@@ -42,6 +44,7 @@ class JudicialPrecedentController extends Controller
'subject' => 'required|string', 'subject' => 'required|string',
'full_text' => 'required|string', 'full_text' => 'required|string',
'issuing_authority' => 'nullable|string', 'issuing_authority' => 'nullable|string',
'category_id' => 'nullable|exists:judicial_precedent_categories,id',
'art_ids' => 'nullable|array', 'art_ids' => 'nullable|array',
'art_ids.*' => 'exists:arts,id' 'art_ids.*' => 'exists:arts,id'
]); ]);
@@ -51,7 +54,8 @@ class JudicialPrecedentController extends Controller
'ruling_date' => $validated['ruling_date'], 'ruling_date' => $validated['ruling_date'],
'subject' => $validated['subject'], 'subject' => $validated['subject'],
'full_text' => $validated['full_text'], 'full_text' => $validated['full_text'],
'issuing_authority' => $validated['issuing_authority'] ?? 'هیأت عمومی دیوان عالی کشور' 'issuing_authority' => $validated['issuing_authority'] ?? 'هیأت عمومی دیوان عالی کشور',
'category_id' => $validated['category_id']
]); ]);
if (!empty($validated['art_ids'])) { if (!empty($validated['art_ids'])) {
@@ -64,9 +68,10 @@ class JudicialPrecedentController extends Controller
public function edit(JudicialPrecedent $judicialPrecedent) public function edit(JudicialPrecedent $judicialPrecedent)
{ {
$arts = Art::all(); $arts = Art::all();
$categories = JudicialPrecedentCategory::all();
$selectedArtIds = $judicialPrecedent->arts->pluck('id')->toArray(); $selectedArtIds = $judicialPrecedent->arts->pluck('id')->toArray();
return view('admin.judicial-precedent.update', compact('judicialPrecedent', 'arts', 'selectedArtIds')); return view('admin.judicial-precedent.update', compact('judicialPrecedent', 'arts', 'categories', 'selectedArtIds'));
} }
public function update(Request $request, JudicialPrecedent $judicialPrecedent) public function update(Request $request, JudicialPrecedent $judicialPrecedent)
@@ -77,6 +82,7 @@ class JudicialPrecedentController extends Controller
'subject' => 'required|string', 'subject' => 'required|string',
'full_text' => 'required|string', 'full_text' => 'required|string',
'issuing_authority' => 'nullable|string', 'issuing_authority' => 'nullable|string',
'category_id' => 'nullable|exists:judicial_precedent_categories,id',
'art_ids' => 'nullable|array', 'art_ids' => 'nullable|array',
'art_ids.*' => 'exists:arts,id' 'art_ids.*' => 'exists:arts,id'
]); ]);

View File

@@ -14,7 +14,8 @@ class JudicialPrecedent extends Model
'ruling_date', 'ruling_date',
'subject', 'subject',
'full_text', 'full_text',
'issuing_authority' 'issuing_authority',
'category_id'
]; ];
protected $hidden = ['created_at', 'updated_at']; protected $hidden = ['created_at', 'updated_at'];
@@ -23,4 +24,9 @@ class JudicialPrecedent extends Model
{ {
return $this->belongsToMany(Art::class, 'art_judicial_precedent'); return $this->belongsToMany(Art::class, 'art_judicial_precedent');
} }
public function category()
{
return $this->belongsTo(JudicialPrecedentCategory::class, 'category_id');
}
} }

View File

@@ -0,0 +1,18 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class JudicialPrecedentCategory extends Model
{
use HasFactory;
protected $fillable = ['name'];
public function judicialPrecedents()
{
return $this->hasMany(JudicialPrecedent::class, 'category_id');
}
}

View File

@@ -0,0 +1,28 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('judicial_precedent_categories', function (Blueprint $table) {
$table->id();
$table->string('name')->unique()->comment('نام دسته‌بندی');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('judicial_precedent_categories');
}
};

View File

@@ -0,0 +1,29 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('judicial_precedents', function (Blueprint $table) {
$table->foreignId('category_id')->nullable()->constrained('judicial_precedent_categories')->onDelete('set null')->comment('دسته‌بندی');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('judicial_precedents', function (Blueprint $table) {
$table->dropForeign(['category_id']);
$table->dropColumn('category_id');
});
}
};

View File

@@ -0,0 +1,25 @@
@extends('admin.layouts.app')
@section('content')
<div class="row">
@include('admin.layouts.errors')
<div class="col-lg-8">
<div class="card">
<div class="card-body">
<h4 class="card-title">افزودن دسته‌بندی رأی وحدت رویه</h4>
<div>
<form action="{{ route('judicial-precedent-category.store') }}" method="post">
@csrf
<div class="mb-4">
<label for="name">نام دسته‌بندی</label>
<input class="form-control" name="name" type="text" placeholder="نام دسته‌بندی" required>
</div>
<button class="btn btn-primary" type="submit">ذخیره</button>
<a href="{{ route('judicial-precedent-category.index') }}" class="btn btn-secondary">بازگشت</a>
</form>
</div>
</div>
</div>
</div>
</div>
@endsection

View File

@@ -0,0 +1,44 @@
@extends('admin.layouts.app')
@section('content')
<div class="row">
<div class="col-12">
<div class="card">
<div class="card-body">
@include('admin.partial.list-filter', ['filterRoute' => 'judicial-precedent-category.index'])
<div id="datatable_wrapper" class="dataTables_wrapper dt-bootstrap4 no-footer">
<div class="row">
<div class="col-sm-12">
<table id="datatable" class="table table-bordered dt-responsive nowrap dataTable no-footer dtr-inline" style="border-collapse: collapse; border-spacing: 0px; width: 100%;" role="grid" aria-describedby="datatable_info">
<thead>
<tr role="row">
<th>نام دسته‌بندی</th>
<th>عملیات</th>
</tr>
</thead>
<tbody>
@foreach ($categories as $category)
<tr>
<td>{{ $category->name }}</td>
<td>
<form action="{{ route('judicial-precedent-category.destroy', $category->id) }}" method="POST" style="display: inline;">
@csrf
@method('DELETE')
<button type="submit" class="btn btn-danger waves-effect waves-light" onclick="return confirm('آیا مطمئنید که می‌خواهید این دسته‌بندی را حذف کنید؟')">حذف</button>
</form>
<a href="{{route('judicial-precedent-category.edit',$category->id)}}" type="button" class="btn btn-primary waves-effect waves-light">ویرایش</a>
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
</div>
<div class="d-flex justify-content-center mt-3">
{{ $categories->withQueryString()->links() }}
</div>
</div>
</div>
</div>
</div>
</div>
@endsection

View File

@@ -0,0 +1,26 @@
@extends('admin.layouts.app')
@section('content')
<div class="row">
@include('admin.layouts.errors')
<div class="col-lg-8">
<div class="card">
<div class="card-body">
<h4 class="card-title">ویرایش دسته‌بندی رأی وحدت رویه</h4>
<div>
<form action="{{ route('judicial-precedent-category.update', $judicialPrecedentCategory->id) }}" method="post">
@csrf
@method('PUT')
<div class="mb-4">
<label for="name">نام دسته‌بندی</label>
<input class="form-control" name="name" type="text" value="{{ $judicialPrecedentCategory->name }}" placeholder="نام دسته‌بندی" required>
</div>
<button class="btn btn-primary" type="submit">بروزرسانی</button>
<a href="{{ route('judicial-precedent-category.index') }}" class="btn btn-secondary">بازگشت</a>
</form>
</div>
</div>
</div>
</div>
</div>
@endsection

View File

@@ -34,6 +34,16 @@
<input class="form-control" name="issuing_authority" type="text" value="هیأت عمومی دیوان عالی کشور" placeholder="مرجع صادر کننده"> <input class="form-control" name="issuing_authority" type="text" value="هیأت عمومی دیوان عالی کشور" placeholder="مرجع صادر کننده">
</div> </div>
<div class="mb-4">
<label for="category_id">دسته‌بندی</label>
<select class="form-control" name="category_id" id="category_id">
<option value="">انتخاب دسته‌بندی</option>
@foreach ($categories as $category)
<option value="{{$category->id}}">{{$category->name}}</option>
@endforeach
</select>
</div>
<div class="mb-4"> <div class="mb-4">
<label for="art_ids">مواد مرتبط</label> <label for="art_ids">مواد مرتبط</label>
<select class="form-control" name="art_ids[]" id="art_ids" multiple size="10"> <select class="form-control" name="art_ids[]" id="art_ids" multiple size="10">

View File

@@ -14,6 +14,7 @@
<th>شماره رأی</th> <th>شماره رأی</th>
<th>تاریخ صدور</th> <th>تاریخ صدور</th>
<th>موضوع</th> <th>موضوع</th>
<th>دسته‌بندی</th>
<th>مرجع صادر کننده</th> <th>مرجع صادر کننده</th>
<th>عملیات</th> <th>عملیات</th>
</tr> </tr>
@@ -24,6 +25,7 @@
<td>{{ $precedent->ruling_number }}</td> <td>{{ $precedent->ruling_number }}</td>
<td>{{ $precedent->ruling_date }}</td> <td>{{ $precedent->ruling_date }}</td>
<td>{{ $precedent->subject }}</td> <td>{{ $precedent->subject }}</td>
<td>{{ $precedent->category?->name }}</td>
<td>{{ $precedent->issuing_authority }}</td> <td>{{ $precedent->issuing_authority }}</td>
<td> <td>
<form action="{{ route('judicial-precedent.destroy', $precedent->id) }}" method="POST" style="display: inline;"> <form action="{{ route('judicial-precedent.destroy', $precedent->id) }}" method="POST" style="display: inline;">

View File

@@ -35,6 +35,16 @@
<input class="form-control" name="issuing_authority" type="text" value="{{ $judicialPrecedent->issuing_authority }}" placeholder="مرجع صادر کننده"> <input class="form-control" name="issuing_authority" type="text" value="{{ $judicialPrecedent->issuing_authority }}" placeholder="مرجع صادر کننده">
</div> </div>
<div class="mb-4">
<label for="category_id">دسته‌بندی</label>
<select class="form-control" name="category_id" id="category_id">
<option value="">انتخاب دسته‌بندی</option>
@foreach ($categories as $category)
<option value="{{$category->id}}" {{ $judicialPrecedent->category_id == $category->id ? 'selected' : '' }}>{{$category->name}}</option>
@endforeach
</select>
</div>
<div class="mb-4"> <div class="mb-4">
<label for="art_ids">مواد مرتبط</label> <label for="art_ids">مواد مرتبط</label>
<select class="form-control" name="art_ids[]" id="art_ids" multiple size="10"> <select class="form-control" name="art_ids[]" id="art_ids" multiple size="10">

View File

@@ -9,7 +9,7 @@ use App\Http\Controllers\Admin\ChapterController;
use App\Http\Controllers\Admin\DivisionController; use App\Http\Controllers\Admin\DivisionController;
use App\Http\Controllers\Admin\GateController; use App\Http\Controllers\Admin\GateController;
use App\Http\Controllers\Admin\HomeController; use App\Http\Controllers\Admin\HomeController;
use App\Http\Controllers\Admin\JudicialPrecedentController; use App\Http\Controllers\Admin\JudicialPrecedentCategoryController;
use App\Http\Controllers\Admin\LawController; use App\Http\Controllers\Admin\LawController;
use App\Http\Controllers\Admin\NotificationController; use App\Http\Controllers\Admin\NotificationController;
use App\Http\Controllers\Admin\PartController; use App\Http\Controllers\Admin\PartController;
@@ -41,5 +41,7 @@ Route::middleware(['auth',config('jetstream.auth_session')])->group(function ()
Route::resource('subscribe-plans', SubscribePlanController::class); Route::resource('subscribe-plans', SubscribePlanController::class);
Route::resource('notifications', NotificationController::class); Route::resource('notifications', NotificationController::class);
Route::resource('judicial-precedent', JudicialPrecedentController::class); Route::resource('judicial-precedent', JudicialPrecedentController::class);
Route::resource('judicial-precedent-category', JudicialPrecedentCategoryController::class);
Route::get('suggestions',[SuggestionController::class,'index'])->name('suggestions.index'); Route::get('suggestions',[SuggestionController::class,'index'])->name('suggestions.index');
}); });