feat(roles): tambahkan fitur pengelolaan posisi dan tingkat jabatan pada modul role
- Modifikasi form pembuatan role: - Tambahkan class `tomselect` pada elemen dropdown posisi. - Update label tingkat jabatan pada tampilan opsi dropdown. - Pembaruan tabel pada halaman list role: - Tambah kolom baru: "Position" dan "Tingkat Jabatan". - Kolom baru dapat diurutkan. - Update logika pencarian dan pengurutan: - Izinkan pencarian berdasarkan nama posisi dan tingkat jabatan. - Tambahkan pengurutan data berdasarkan nama posisi dan tingkat jabatan dengan join table `positions`. - Perbaikan pada paginasi dan penghitungan data: - Revisi query agar menghindari duplikasi data akibat join tabel. - Ekspor data: - Tambahkan informasi kolom baru "Position" dan "Tingkat Jabatan" pada file Excel hasil ekspor. - Perbarui header dan pengaturan format kolom pada file Excel. Perubahan ini memperluas fleksibilitas pada manajemen role dengan menambahkan dimensi posisi dan tingkat jabatan baik dalam tampilan UI maupun data backend.
This commit is contained in:
@@ -11,13 +11,15 @@ use Modules\Usermanagement\Models\Role;
|
||||
class RolesExport implements WithColumnFormatting, WithHeadings, FromCollection, withMapping
|
||||
{
|
||||
public function collection(){
|
||||
return Role::all();
|
||||
return Role::with('position')->get();
|
||||
}
|
||||
|
||||
public function map($row): array{
|
||||
return [
|
||||
$row->id,
|
||||
$row->name,
|
||||
$row->position ? $row->position->name : '-',
|
||||
$row->position ? $row->position->level : '-',
|
||||
$row->created_at
|
||||
];
|
||||
}
|
||||
@@ -25,6 +27,8 @@ class RolesExport implements WithColumnFormatting, WithHeadings, FromCollection,
|
||||
return [
|
||||
'ID',
|
||||
'Role',
|
||||
'Position',
|
||||
'Tingkat Jabatan',
|
||||
'Created At'
|
||||
];
|
||||
}
|
||||
@@ -32,7 +36,8 @@ class RolesExport implements WithColumnFormatting, WithHeadings, FromCollection,
|
||||
public function columnFormats(): array{
|
||||
return [
|
||||
'A' => \PhpOffice\PhpSpreadsheet\Style\NumberFormat::FORMAT_NUMBER,
|
||||
'C' => \PhpOffice\PhpSpreadsheet\Style\NumberFormat::FORMAT_DATE_DATETIME
|
||||
'D' => \PhpOffice\PhpSpreadsheet\Style\NumberFormat::FORMAT_NUMBER,
|
||||
'E' => \PhpOffice\PhpSpreadsheet\Style\NumberFormat::FORMAT_DATE_DATETIME
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -286,7 +286,11 @@
|
||||
if ($request->has('search') && !empty($request->get('search'))) {
|
||||
$search = $request->get('search');
|
||||
$query->where(function ($q) use ($search) {
|
||||
$q->whereRaw('LOWER(name) LIKE ?', ['%' . strtolower($search) . '%']);
|
||||
$q->whereRaw('LOWER(name) LIKE ?', ['%' . strtolower($search) . '%'])
|
||||
->orWhereHas('position', function($query) use ($search) {
|
||||
$query->whereRaw('LOWER(name) LIKE ?', ['%' . strtolower($search) . '%'])
|
||||
->orWhereRaw('CAST(level AS TEXT) LIKE ?', ['%' . $search . '%']);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -294,11 +298,26 @@
|
||||
if ($request->has('sortOrder') && !empty($request->get('sortOrder'))) {
|
||||
$order = $request->get('sortOrder');
|
||||
$column = $request->get('sortField');
|
||||
$query->orderBy($column, $order);
|
||||
|
||||
// Handle sorting for position-related columns
|
||||
if ($column === 'position_name') {
|
||||
$query->leftJoin('positions', 'roles.position_id', '=', 'positions.id')
|
||||
->orderBy('positions.name', $order)
|
||||
->select('roles.*'); // Select only from roles table to avoid column conflicts
|
||||
} else if ($column === 'level') {
|
||||
$query->leftJoin('positions', 'roles.position_id', '=', 'positions.id')
|
||||
->orderBy('positions.level', $order)
|
||||
->select('roles.*'); // Select only from roles table to avoid column conflicts
|
||||
} else {
|
||||
$query->orderBy($column, $order);
|
||||
}
|
||||
}
|
||||
|
||||
// Get the total count of records
|
||||
$totalRecords = $query->count();
|
||||
// Create a copy of the query for counting
|
||||
$countQuery = clone $query;
|
||||
|
||||
// Get the total count of records (without joins to avoid duplicates)
|
||||
$totalRecords = Role::count();
|
||||
|
||||
// Apply pagination if provided
|
||||
if ($request->has('page') && $request->has('size')) {
|
||||
@@ -309,11 +328,11 @@
|
||||
$query->skip($offset)->take($size);
|
||||
}
|
||||
|
||||
// Get the filtered count of records
|
||||
$filteredRecords = $query->count();
|
||||
// Get the filtered count of records - use distinct to avoid duplicates from joins
|
||||
$filteredRecords = $countQuery->distinct()->count('roles.id');
|
||||
|
||||
// Get the data for the current page
|
||||
$roles = $query->get();
|
||||
$roles = $query->with('position')->get();
|
||||
|
||||
// Calculate the page count
|
||||
$pageCount = ceil($totalRecords/$request->get('size'));
|
||||
|
||||
@@ -38,11 +38,11 @@
|
||||
Position
|
||||
</label>
|
||||
<div class="flex flex-wrap items-baseline w-full">
|
||||
<select class="select @error('position_id') border-danger @enderror" name="position_id">
|
||||
<select class="select tomselect @error('position_id') border-danger @enderror" name="position_id">
|
||||
<option value="">Select Position</option>
|
||||
@foreach($positions as $position)
|
||||
<option value="{{ $position->id }}" {{ (isset($role) && $role->position_id == $position->id) ? 'selected' : '' }}>
|
||||
{{ $position->name }} (Level: {{ $position->level }})
|
||||
{{ $position->name }} | Tingkat Jabatan: {{ $position->level }}
|
||||
</option>
|
||||
@endforeach
|
||||
</select>
|
||||
|
||||
@@ -19,29 +19,7 @@
|
||||
|
||||
</label>
|
||||
</div>
|
||||
<div class="flex flex-wrap gap-2.5">
|
||||
<select class="select select-sm w-28">
|
||||
<option value="1">
|
||||
Active
|
||||
</option>
|
||||
<option value="2">
|
||||
Disabled
|
||||
</option>
|
||||
<option value="2">
|
||||
Pending
|
||||
</option>
|
||||
</select>
|
||||
<select class="select select-sm w-28">
|
||||
<option value="desc">
|
||||
Latest
|
||||
</option>
|
||||
<option value="asc">
|
||||
Oldest
|
||||
</option>
|
||||
</select>
|
||||
<button class="btn btn-sm btn-outline btn-primary">
|
||||
<i class="ki-filled ki-setting-4"> </i> <Filters></Filters>
|
||||
</button>
|
||||
<div class="flex flex-wrap gap-2.5 lg:gap-5">
|
||||
<div class="h-[24px] border border-r-gray-200"> </div>
|
||||
<a class="btn btn-sm btn-light" href="{{ route('users.roles.export') }}"> Export to Excel </a>
|
||||
<a class="btn btn-sm btn-primary" href="{{ route('users.roles.create') }}"> Add Role </a>
|
||||
@@ -60,6 +38,14 @@
|
||||
<span class="sort"> <span class="sort-label"> Role </span>
|
||||
<span class="sort-icon"> </span> </span>
|
||||
</th>
|
||||
<th class="min-w-[200px]" data-datatable-column="position_name">
|
||||
<span class="sort"> <span class="sort-label"> Position </span>
|
||||
<span class="sort-icon"> </span> </span>
|
||||
</th>
|
||||
<th class="min-w-[100px]" data-datatable-column="level">
|
||||
<span class="sort"> <span class="sort-label"> Tingkat Jabatan </span>
|
||||
<span class="sort-icon"> </span> </span>
|
||||
</th>
|
||||
<th class="min-w-[50px] text-center" data-datatable-column="actions">Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
@@ -138,6 +124,20 @@
|
||||
name: {
|
||||
title: 'Role',
|
||||
},
|
||||
position_name: {
|
||||
title: 'Position',
|
||||
render: (item, data) => {
|
||||
return data.position ? data.position.name : '-';
|
||||
},
|
||||
sortable: true,
|
||||
},
|
||||
level: {
|
||||
title: 'Level',
|
||||
render: (item, data) => {
|
||||
return data.position ? data.position.level : '-';
|
||||
},
|
||||
sortable: true,
|
||||
},
|
||||
actions: {
|
||||
title: 'Status',
|
||||
render: (item, data) => {
|
||||
@@ -162,4 +162,3 @@
|
||||
});
|
||||
</script>
|
||||
@endpush
|
||||
|
||||
|
||||
Reference in New Issue
Block a user