first
This commit is contained in:
26
app/Http/Controllers/Admin/AuditController.php
Normal file
26
app/Http/Controllers/Admin/AuditController.php
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\AuditLog;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\View\View;
|
||||
|
||||
class AuditController extends Controller
|
||||
{
|
||||
public function index(Request $request): View
|
||||
{
|
||||
$action = $request->query('action');
|
||||
|
||||
$logs = AuditLog::with('user')
|
||||
->when($action, fn ($q) => $q->where('action', $action))
|
||||
->latest()
|
||||
->paginate(40)
|
||||
->withQueryString();
|
||||
|
||||
$actions = AuditLog::query()->distinct()->orderBy('action')->pluck('action');
|
||||
|
||||
return view('admin.audit.index', compact('logs', 'actions', 'action'));
|
||||
}
|
||||
}
|
||||
91
app/Http/Controllers/Admin/MemberController.php
Normal file
91
app/Http/Controllers/Admin/MemberController.php
Normal file
@@ -0,0 +1,91 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\AuditLog;
|
||||
use App\Models\ImportLog;
|
||||
use App\Models\Member;
|
||||
use App\Services\MemberImportService;
|
||||
use App\Support\Spreadsheet;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\View\View;
|
||||
|
||||
class MemberController extends Controller
|
||||
{
|
||||
public function index(Request $request): View
|
||||
{
|
||||
$q = $request->query('q');
|
||||
$members = Member::query()
|
||||
->when($q, fn ($query) => $query->search($q))
|
||||
->withCount(['drawResults as confirmed_wins' => fn ($query) => $query->where('status', \App\Models\DrawResult::STATUS_CONFIRMED)])
|
||||
->with('attendance')
|
||||
->orderBy('nama')
|
||||
->paginate(25)
|
||||
->withQueryString();
|
||||
|
||||
$importLogs = ImportLog::where('type', 'members')->with('importedBy')->latest()->take(5)->get();
|
||||
|
||||
return view('admin.members.index', compact('members', 'q', 'importLogs'));
|
||||
}
|
||||
|
||||
public function edit(Member $member): View
|
||||
{
|
||||
return view('admin.members.edit', compact('member'));
|
||||
}
|
||||
|
||||
public function update(Request $request, Member $member): RedirectResponse
|
||||
{
|
||||
$data = $request->validate([
|
||||
'no_anggota' => ['nullable', 'string', 'max:255'],
|
||||
'no_pekerja' => ['nullable', 'string', 'max:255', "unique:members,no_pekerja,{$member->id}"],
|
||||
'no_kp' => ['nullable', 'string', 'max:255', "unique:members,no_kp,{$member->id}"],
|
||||
'nama' => ['required', 'string', 'max:255'],
|
||||
'jabatan' => ['nullable', 'string', 'max:255'],
|
||||
'bahagian' => ['nullable', 'string', 'max:255'],
|
||||
'telefon' => ['nullable', 'string', 'max:255'],
|
||||
'status_aktif' => ['required', 'boolean'],
|
||||
]);
|
||||
|
||||
$member->update($data);
|
||||
AuditLog::record('member.update', "Kemaskini anggota: {$member->nama}", $member);
|
||||
|
||||
return redirect()->route('admin.members.index')->with('success', 'Maklumat anggota dikemaskini.');
|
||||
}
|
||||
|
||||
public function destroy(Member $member): RedirectResponse
|
||||
{
|
||||
$nama = $member->nama;
|
||||
$member->delete();
|
||||
AuditLog::record('member.delete', "Padam anggota: {$nama}");
|
||||
|
||||
return redirect()->route('admin.members.index')->with('success', "Anggota '{$nama}' dipadam.");
|
||||
}
|
||||
|
||||
public function showImport(): View
|
||||
{
|
||||
$logs = ImportLog::where('type', 'members')->with('importedBy')->latest()->take(15)->get();
|
||||
|
||||
return view('admin.members.import', compact('logs'));
|
||||
}
|
||||
|
||||
public function import(Request $request, MemberImportService $service): RedirectResponse
|
||||
{
|
||||
$request->validate([
|
||||
'file' => ['required', 'file', 'mimes:csv,txt,xlsx,xls', 'max:10240'],
|
||||
]);
|
||||
|
||||
$file = $request->file('file');
|
||||
$rows = Spreadsheet::read($file->getRealPath(), $file->getClientOriginalExtension());
|
||||
|
||||
$log = $service->import($rows, $file->getClientOriginalName(), $request->user()->id);
|
||||
AuditLog::record('member.import', "Import anggota: {$log->filename}", $log, [
|
||||
'success' => $log->success_count,
|
||||
'duplicate' => $log->duplicate_count,
|
||||
'failed' => $log->failed_count,
|
||||
]);
|
||||
|
||||
return redirect()->route('admin.members.import')->with('import_result', $log->id);
|
||||
}
|
||||
}
|
||||
83
app/Http/Controllers/Admin/PrizeController.php
Normal file
83
app/Http/Controllers/Admin/PrizeController.php
Normal file
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\AuditLog;
|
||||
use App\Models\ImportLog;
|
||||
use App\Models\Prize;
|
||||
use App\Services\PrizeImportService;
|
||||
use App\Support\Spreadsheet;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\View\View;
|
||||
|
||||
class PrizeController extends Controller
|
||||
{
|
||||
public function index(): View
|
||||
{
|
||||
$prizes = Prize::query()->ordered()->with('drawResults.member')->paginate(30);
|
||||
$importLogs = ImportLog::where('type', 'prizes')->with('importedBy')->latest()->take(5)->get();
|
||||
|
||||
return view('admin.prizes.index', compact('prizes', 'importLogs'));
|
||||
}
|
||||
|
||||
public function edit(Prize $prize): View
|
||||
{
|
||||
return view('admin.prizes.edit', compact('prize'));
|
||||
}
|
||||
|
||||
public function update(Request $request, Prize $prize): RedirectResponse
|
||||
{
|
||||
$data = $request->validate([
|
||||
'kod_hadiah' => ['nullable', 'string', 'max:255'],
|
||||
'nama_hadiah' => ['required', 'string', 'max:255'],
|
||||
'kategori' => ['nullable', 'string', 'max:255'],
|
||||
'nilai_anggaran' => ['nullable', 'numeric', 'min:0'],
|
||||
'draw_order' => ['required', 'integer', 'min:0'],
|
||||
]);
|
||||
|
||||
$prize->update($data);
|
||||
AuditLog::record('prize.update', "Kemaskini hadiah: {$prize->nama_hadiah}", $prize);
|
||||
|
||||
return redirect()->route('admin.prizes.index')->with('success', 'Maklumat hadiah dikemaskini.');
|
||||
}
|
||||
|
||||
public function destroy(Prize $prize): RedirectResponse
|
||||
{
|
||||
if ($prize->status === Prize::STATUS_DISAHKAN) {
|
||||
return back()->with('error', 'Hadiah yang sudah ada pemenang disahkan tidak boleh dipadam.');
|
||||
}
|
||||
|
||||
$nama = $prize->nama_hadiah;
|
||||
$prize->delete();
|
||||
AuditLog::record('prize.delete', "Padam hadiah: {$nama}");
|
||||
|
||||
return redirect()->route('admin.prizes.index')->with('success', "Hadiah '{$nama}' dipadam.");
|
||||
}
|
||||
|
||||
public function showImport(): View
|
||||
{
|
||||
$logs = ImportLog::where('type', 'prizes')->with('importedBy')->latest()->take(15)->get();
|
||||
|
||||
return view('admin.prizes.import', compact('logs'));
|
||||
}
|
||||
|
||||
public function import(Request $request, PrizeImportService $service): RedirectResponse
|
||||
{
|
||||
$request->validate([
|
||||
'file' => ['required', 'file', 'mimes:csv,txt,xlsx,xls', 'max:10240'],
|
||||
]);
|
||||
|
||||
$file = $request->file('file');
|
||||
$rows = Spreadsheet::read($file->getRealPath(), $file->getClientOriginalExtension());
|
||||
|
||||
$log = $service->import($rows, $file->getClientOriginalName(), $request->user()->id);
|
||||
AuditLog::record('prize.import', "Import hadiah: {$log->filename}", $log, [
|
||||
'success' => $log->success_count,
|
||||
'failed' => $log->failed_count,
|
||||
]);
|
||||
|
||||
return redirect()->route('admin.prizes.import')->with('import_result', $log->id);
|
||||
}
|
||||
}
|
||||
60
app/Http/Controllers/Admin/SettingController.php
Normal file
60
app/Http/Controllers/Admin/SettingController.php
Normal file
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\AttendanceRecord;
|
||||
use App\Models\AuditLog;
|
||||
use App\Models\DrawResult;
|
||||
use App\Models\DrawSession;
|
||||
use App\Models\Prize;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\View\View;
|
||||
|
||||
class SettingController extends Controller
|
||||
{
|
||||
public function index(): View
|
||||
{
|
||||
$session = DrawSession::active();
|
||||
|
||||
return view('admin.settings.index', compact('session'));
|
||||
}
|
||||
|
||||
public function updateSession(Request $request): RedirectResponse
|
||||
{
|
||||
$data = $request->validate([
|
||||
'nama' => ['required', 'string', 'max:255'],
|
||||
'return_cancelled_to_pool' => ['required', 'boolean'],
|
||||
]);
|
||||
|
||||
$session = DrawSession::active();
|
||||
$session->update($data);
|
||||
AuditLog::record('setting.session', 'Kemaskini tetapan sesi cabutan', $session, $data);
|
||||
|
||||
return back()->with('success', 'Tetapan sesi dikemaskini.');
|
||||
}
|
||||
|
||||
/** Reset data kehadiran & cabutan untuk event baru */
|
||||
public function reset(Request $request): RedirectResponse
|
||||
{
|
||||
$request->validate([
|
||||
'confirm' => ['required', 'in:RESET'],
|
||||
'scope' => ['required', 'in:all,draw'],
|
||||
]);
|
||||
|
||||
DB::transaction(function () use ($request) {
|
||||
DrawResult::query()->delete();
|
||||
Prize::query()->update(['status' => Prize::STATUS_BELUM, 'redraw_count' => 0]);
|
||||
|
||||
if ($request->scope === 'all') {
|
||||
AttendanceRecord::query()->delete();
|
||||
}
|
||||
});
|
||||
|
||||
AuditLog::record('setting.reset', 'Reset data event', null, ['scope' => $request->scope]);
|
||||
|
||||
return back()->with('success', 'Data event berjaya direset.');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user