556 lines
21 KiB
PHP
556 lines
21 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Admin;
|
|
|
|
use App\Http\Controllers\Controller;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\Log;
|
|
use Carbon\Carbon;
|
|
use Carbon\CarbonPeriod;
|
|
|
|
class SuperAdminController extends Controller
|
|
{
|
|
private function apiUrl($endpoint = '')
|
|
{
|
|
return rtrim(env('BACKEND_API_URL'), '/') . '/' . ltrim($endpoint, '/');
|
|
}
|
|
|
|
public function index()
|
|
{
|
|
$response = \Illuminate\Support\Facades\Http::withToken(session('api_token'))
|
|
->get($this->apiUrl('/penugasan'), ['is_archived' => 'false']);
|
|
|
|
$dashResponse = \Illuminate\Support\Facades\Http::withToken(session('api_token'))
|
|
->get($this->apiUrl('/dashboard'));
|
|
|
|
$items = collect([]);
|
|
if ($response->successful()) {
|
|
$items = collect($response->json()['data'])->map(function($item) {
|
|
return (object) [
|
|
'id' => $item['id'],
|
|
'nama_kegiatan' => $item['kegiatan'],
|
|
'tanggal' => $item['tanggal_mulai'],
|
|
'tanggal_selesai' => $item['tanggal_selesai'] ?? null,
|
|
'created_at' => \Carbon\Carbon::parse($item['created_at']),
|
|
'status' => $item['status'] == 'proses' ? 'on_progres' : $item['status'],
|
|
'user' => (object) ['name' => $item['pembuat']['name'] ?? 'System'],
|
|
'petugas' => $item['petugas'] ?? [],
|
|
'pembuat' => $item['pembuat'] ?? []
|
|
];
|
|
});
|
|
}
|
|
|
|
$allItems = clone $items;
|
|
$items = $items->filter(function($item) {
|
|
return $item->status !== 'dibatalkan';
|
|
})->values();
|
|
|
|
// Manual Pagination
|
|
$perPage = 10;
|
|
$currentPage = \Illuminate\Pagination\Paginator::resolveCurrentPage();
|
|
$currentItems = $items->slice(($currentPage - 1) * $perPage, $perPage)->all();
|
|
$activities = new \Illuminate\Pagination\LengthAwarePaginator($currentItems, count($items), $perPage, $currentPage, [
|
|
'path' => \Illuminate\Pagination\Paginator::resolveCurrentPath()
|
|
]);
|
|
|
|
$stats = [
|
|
'total' => $items->count(),
|
|
'users' => 0, // diisi nanti
|
|
'proses' => $items->where('status', 'on_progres')->count(),
|
|
'deleted' => $allItems->where('status', 'dibatalkan')->count(),
|
|
];
|
|
|
|
// Ambil User
|
|
$usersResponse = \Illuminate\Support\Facades\Http::withToken(session('api_token'))
|
|
->get($this->apiUrl('/users'));
|
|
$users = collect([]);
|
|
if ($usersResponse->successful()) {
|
|
$users = collect($usersResponse->json()['data']);
|
|
$stats['users'] = $users->count();
|
|
}
|
|
|
|
// ── Top 5 Petugas (Dihitung dari penugasan)
|
|
$topUsers = $users->map(function($u) use ($items) {
|
|
$count = $items->filter(function($item) use ($u) {
|
|
if (isset($item->petugas) && is_array($item->petugas)) {
|
|
foreach ($item->petugas as $p) {
|
|
if (isset($p['id']) && $p['id'] == $u['id']) return true;
|
|
}
|
|
}
|
|
return isset($item->pembuat['id']) && $item->pembuat['id'] == $u['id'];
|
|
})->count();
|
|
|
|
return (object) [
|
|
'name' => $u['name'] ?? 'System',
|
|
'activities_count' => $count
|
|
];
|
|
})->sortByDesc('activities_count')->take(5)->values();
|
|
|
|
// ── Data Grafik
|
|
$chartData = $this->buildChartData($items);
|
|
|
|
$system = [
|
|
'server' => rand(25, 55),
|
|
'database' => rand(45, 75),
|
|
'storage' => rand(60, 85),
|
|
];
|
|
|
|
return view('superadmin.dashboard', compact(
|
|
'activities',
|
|
'stats',
|
|
'topUsers',
|
|
'chartData',
|
|
'system'
|
|
));
|
|
}
|
|
|
|
private function buildChartData($items)
|
|
{
|
|
$now = Carbon::now();
|
|
|
|
// ── MINGGU INI ─────────────────────────────────
|
|
$startOfWeek = $now->copy()->startOfWeek(Carbon::MONDAY);
|
|
$endOfWeek = $now->copy()->endOfWeek(Carbon::SUNDAY);
|
|
|
|
$weekLabels = ['Sen', 'Sel', 'Rab', 'Kam', 'Jum', 'Sab', 'Min'];
|
|
$weekValues = array_fill(0, 7, 0);
|
|
|
|
foreach ($items as $item) {
|
|
$date = $item->created_at;
|
|
if ($date->between($startOfWeek, $endOfWeek)) {
|
|
$idx = $date->dayOfWeekIso - 1;
|
|
$weekValues[$idx]++;
|
|
}
|
|
}
|
|
|
|
// ── BULAN INI ──────────────────────────────
|
|
$startOfMonth = $now->copy()->startOfMonth();
|
|
$endOfMonth = $now->copy()->endOfMonth();
|
|
$daysInMonth = $now->daysInMonth;
|
|
|
|
$monthLabels = [];
|
|
$monthValues = array_fill(0, $daysInMonth, 0);
|
|
|
|
for ($i = 1; $i <= $daysInMonth; $i++) {
|
|
$monthLabels[] = ($i % 5 === 1 || $i === 1) ? (string) $i : '';
|
|
}
|
|
|
|
foreach ($items as $item) {
|
|
$date = $item->created_at;
|
|
if ($date->between($startOfMonth, $endOfMonth)) {
|
|
$monthValues[$date->day - 1]++;
|
|
}
|
|
}
|
|
|
|
// ── TAHUN INI ────────────────────────────────
|
|
$monthNames = ['Jan', 'Feb', 'Mar', 'Apr', 'Mei', 'Jun', 'Jul', 'Ags', 'Sep', 'Okt', 'Nov', 'Des'];
|
|
$yearValues = array_fill(0, 12, 0);
|
|
|
|
foreach ($items as $item) {
|
|
$date = $item->created_at;
|
|
if ($date->year === $now->year) {
|
|
$yearValues[$date->month - 1]++;
|
|
}
|
|
}
|
|
|
|
return [
|
|
'week' => [
|
|
'labels' => $weekLabels,
|
|
'values' => $weekValues,
|
|
'todayIndex' => $now->dayOfWeekIso - 1,
|
|
],
|
|
'month' => [
|
|
'labels' => $monthLabels,
|
|
'values' => $monthValues,
|
|
'todayIndex' => $now->day - 1,
|
|
],
|
|
'year' => [
|
|
'labels' => $monthNames,
|
|
'values' => $yearValues,
|
|
'todayIndex' => $now->month - 1,
|
|
],
|
|
];
|
|
}
|
|
|
|
public function show($id)
|
|
{
|
|
$response = \Illuminate\Support\Facades\Http::withToken(session('api_token'))
|
|
->get($this->apiUrl('/penugasan/' . $id));
|
|
|
|
if (!$response->successful()) {
|
|
return redirect()->back()->with('error', 'Kegiatan tidak ditemukan.');
|
|
}
|
|
$data = $response->json()['data'];
|
|
$activity = (object) [
|
|
'id' => $data['id'],
|
|
'nama_kegiatan' => $data['kegiatan'],
|
|
'tanggal' => $data['tanggal_mulai'],
|
|
'tanggal_selesai' => $data['tanggal_selesai'] ?? null,
|
|
'status' => $data['status'] == 'proses' ? 'on_progres' : $data['status'],
|
|
'deskripsi' => $data['keterangan'] ?? '-',
|
|
'lokasi' => $data['lokasi'] ?? '-',
|
|
'status_note' => $data['status_note'] ?? null,
|
|
'updated_at' => \Carbon\Carbon::parse($data['updated_at'] ?? now()),
|
|
'user' => (object) ['name' => $data['pembuat']['name'] ?? 'System'],
|
|
'petugas' => $data['petugas'] ?? [],
|
|
'nomor_surat' => $data['nomor_surat'] ?? '-',
|
|
'progress' => $data['progress'] ?? []
|
|
];
|
|
|
|
return view('superadmin.kegiatan.show', compact('activity'));
|
|
}
|
|
|
|
public function approve(Request $request, $id)
|
|
{
|
|
$response = \Illuminate\Support\Facades\Http::withToken(session('api_token'))
|
|
->post($this->apiUrl("/penugasan/{$id}/update-status"), [
|
|
'status' => 'telah_ditinjau'
|
|
]);
|
|
|
|
if ($response->successful()) {
|
|
return redirect()->back()->with('success', 'Kegiatan berhasil disetujui (Telah Ditinjau).');
|
|
}
|
|
|
|
return redirect()->back()->with('error', 'Terjadi kesalahan saat menyetujui kegiatan.');
|
|
}
|
|
|
|
public function revision(Request $request, $id)
|
|
{
|
|
$request->validate([
|
|
'status_note' => 'required|string|min:5|max:255'
|
|
]);
|
|
|
|
$response = \Illuminate\Support\Facades\Http::withToken(session('api_token'))
|
|
->post($this->apiUrl("/penugasan/{$id}/update-status"), [
|
|
'status' => 'proses',
|
|
'status_note' => 'REVISI dari ' . session('user_name') . ': ' . $request->status_note
|
|
]);
|
|
|
|
if ($response->successful()) {
|
|
return redirect()->back()->with('success', 'Kegiatan dikembalikan ke pegawai untuk direvisi.');
|
|
}
|
|
|
|
return redirect()->back()->with('error', 'Terjadi kesalahan saat meminta revisi.');
|
|
}
|
|
|
|
public function destroy(Request $request, $id)
|
|
{
|
|
$request->validate([
|
|
'alasan_hapus' => 'required|string|min:10|max:500',
|
|
]);
|
|
|
|
$response = \Illuminate\Support\Facades\Http::withToken(session('api_token'))
|
|
->post($this->apiUrl("/penugasan/{$id}/delete"), [
|
|
'alasan' => $request->alasan_hapus
|
|
]);
|
|
|
|
if ($response->successful()) {
|
|
return redirect()->back()->with('success', 'Kegiatan berhasil dibatalkan dan dicatat dalam log.');
|
|
}
|
|
|
|
return redirect()->back()->with('error', 'Gagal membatalkan kegiatan.');
|
|
}
|
|
|
|
public function arsip()
|
|
{
|
|
$response = \Illuminate\Support\Facades\Http::withToken(session('api_token'))
|
|
->get($this->apiUrl('/penugasan'), ['is_archived' => 'true']);
|
|
|
|
$items = collect([]);
|
|
if ($response->successful()) {
|
|
$items = collect($response->json()['data'])->map(function($item) {
|
|
return (object) [
|
|
'id' => $item['id'],
|
|
'nama_kegiatan' => $item['kegiatan'],
|
|
'tanggal' => $item['tanggal_mulai'],
|
|
'tanggal_selesai' => $item['tanggal_selesai'] ?? null,
|
|
'created_at' => \Carbon\Carbon::parse($item['created_at']),
|
|
'status' => $item['status'] == 'proses' ? 'on_progres' : $item['status'],
|
|
'user' => (object) ['name' => $item['pembuat']['name'] ?? 'System'],
|
|
'petugas' => $item['petugas'] ?? [],
|
|
'pembuat' => $item['pembuat'] ?? []
|
|
];
|
|
});
|
|
}
|
|
|
|
// Manual Pagination
|
|
$perPage = 10;
|
|
$currentPage = \Illuminate\Pagination\Paginator::resolveCurrentPage();
|
|
$currentItems = $items->slice(($currentPage - 1) * $perPage, $perPage)->all();
|
|
$activities = new \Illuminate\Pagination\LengthAwarePaginator($currentItems, count($items), $perPage, $currentPage, [
|
|
'path' => \Illuminate\Pagination\Paginator::resolveCurrentPath()
|
|
]);
|
|
|
|
return view('superadmin.arsip.index', compact('activities'));
|
|
}
|
|
|
|
public function archive($id)
|
|
{
|
|
$response = \Illuminate\Support\Facades\Http::withToken(session('api_token'))
|
|
->post($this->apiUrl("/penugasan/{$id}/archive"));
|
|
|
|
if ($response->successful()) {
|
|
return redirect()->back()->with('success', 'Status arsip laporan berhasil diperbarui.');
|
|
}
|
|
|
|
return redirect()->back()->with('error', 'Gagal memperbarui status arsip laporan.');
|
|
}
|
|
|
|
public function userIndex()
|
|
{
|
|
// Panggil API Penugasan untuk menghitung activities dinamis
|
|
$penugasanResponse = \Illuminate\Support\Facades\Http::withToken(session('api_token'))
|
|
->get($this->apiUrl('/penugasan'));
|
|
$items = collect([]);
|
|
if ($penugasanResponse->successful()) {
|
|
$items = collect($penugasanResponse->json()['data']);
|
|
}
|
|
|
|
// Panggil API Users
|
|
$response = \Illuminate\Support\Facades\Http::withToken(session('api_token'))
|
|
->get($this->apiUrl('/users'));
|
|
|
|
$users = collect([]);
|
|
if ($response->successful()) {
|
|
$users = collect($response->json()['data'])->map(function($u) use ($items) {
|
|
$activitiesCount = $items->filter(function($item) use ($u) {
|
|
// Cek apakah user ada di array petugas
|
|
if (isset($item['petugas']) && is_array($item['petugas'])) {
|
|
foreach ($item['petugas'] as $p) {
|
|
if ($p['id'] == $u['id']) return true;
|
|
}
|
|
}
|
|
// Fallback cek pembuat
|
|
return ($item['pembuat']['id'] ?? null) == $u['id'];
|
|
})->count();
|
|
|
|
return (object) [
|
|
'id' => $u['id'],
|
|
'name' => $u['name'],
|
|
'username' => $u['username'],
|
|
'role' => $u['role'],
|
|
'created_at' => isset($u['created_at']) ? \Carbon\Carbon::parse($u['created_at']) : now(),
|
|
'activities_count' => $activitiesCount
|
|
];
|
|
});
|
|
}
|
|
|
|
// Manual Pagination
|
|
$perPage = 15;
|
|
$currentPage = \Illuminate\Pagination\Paginator::resolveCurrentPage();
|
|
$currentItems = $users->slice(($currentPage - 1) * $perPage, $perPage)->all();
|
|
$paginatedUsers = new \Illuminate\Pagination\LengthAwarePaginator($currentItems, $users->count(), $perPage, $currentPage, [
|
|
'path' => \Illuminate\Pagination\Paginator::resolveCurrentPath()
|
|
]);
|
|
|
|
$stats = [
|
|
'total' => $users->count(),
|
|
'active' => $users->where('activities_count', '>', 0)->count(),
|
|
'activities' => $users->sum('activities_count'),
|
|
'max_activities' => max($users->max('activities_count') ?? 1, 1),
|
|
];
|
|
|
|
return view('superadmin.user.index', ['users' => $paginatedUsers, 'stats' => $stats]);
|
|
}
|
|
|
|
public function createUser()
|
|
{
|
|
return view('superadmin.user.create-user');
|
|
}
|
|
|
|
public function storeUser(Request $request)
|
|
{
|
|
$request->validate([
|
|
'name' => 'required|string',
|
|
'username' => 'required|string',
|
|
'password' => 'required|string|min:6',
|
|
'role' => 'required|in:user,admin,superadmin',
|
|
]);
|
|
|
|
$response = \Illuminate\Support\Facades\Http::withToken(session('api_token'))
|
|
->acceptJson()
|
|
->post($this->apiUrl('/register'), [
|
|
'name' => $request->name,
|
|
'username' => $request->username,
|
|
'password' => $request->password,
|
|
'role' => $request->role,
|
|
]);
|
|
|
|
if ($response->successful()) {
|
|
return redirect()->route('admin.superadmin.user.index')->with('success', 'Pengguna berhasil ditambahkan');
|
|
}
|
|
|
|
if ($response->status() === 422) {
|
|
return back()->withErrors($response->json('errors'))->withInput();
|
|
}
|
|
|
|
return back()->with('error', $response->json('message') ?? 'Gagal menambah pengguna')->withInput();
|
|
}
|
|
|
|
public function editUser($id)
|
|
{
|
|
$response = \Illuminate\Support\Facades\Http::withToken(session('api_token'))
|
|
->get($this->apiUrl("/users/{$id}"));
|
|
|
|
if ($response->successful()) {
|
|
$userData = $response->json()['data'];
|
|
$user = (object) [
|
|
'id' => $userData['id'],
|
|
'name' => $userData['name'],
|
|
'username' => $userData['username'],
|
|
'role' => $userData['role'],
|
|
'email' => $userData['email'] ?? '',
|
|
'created_at' => isset($userData['created_at'])
|
|
? \Carbon\Carbon::parse($userData['created_at'])
|
|
: now(),
|
|
];
|
|
return view('superadmin.user.edit-user', compact('user'));
|
|
}
|
|
return redirect()->back()->with('error', 'User tidak ditemukan atau gagal mengambil data.');
|
|
}
|
|
|
|
public function updateUser(Request $request, $id)
|
|
{
|
|
$request->validate([
|
|
'name' => 'required',
|
|
'username' => 'required',
|
|
'role' => 'required',
|
|
'password' => 'nullable|min:6|confirmed',
|
|
]);
|
|
|
|
$payload = $request->only('name', 'username', 'role');
|
|
if ($request->filled('password')) {
|
|
$payload['password'] = $request->password;
|
|
}
|
|
|
|
$response = \Illuminate\Support\Facades\Http::withToken(session('api_token'))
|
|
->acceptJson()
|
|
->put($this->apiUrl("/users/{$id}"), $payload);
|
|
|
|
if ($response->successful()) {
|
|
return redirect()->route('admin.superadmin.user.index')->with('success', 'User berhasil diupdate');
|
|
}
|
|
|
|
if ($response->status() === 422) {
|
|
return back()->withErrors($response->json('errors'))->withInput();
|
|
}
|
|
|
|
return redirect()->back()->with('error', 'Gagal update user.')->withInput();
|
|
}
|
|
|
|
// 🔥 DELETE USER
|
|
public function destroyUser($id)
|
|
{
|
|
$response = \Illuminate\Support\Facades\Http::withToken(session('api_token'))
|
|
->delete($this->apiUrl('/users/' . $id));
|
|
|
|
if ($response->successful()) {
|
|
return redirect()->route('admin.superadmin.user.index')->with('success', 'Pengguna berhasil dihapus');
|
|
}
|
|
|
|
return back()->with('error', 'Gagal menghapus pengguna');
|
|
}
|
|
|
|
// 🔥 CREATE KEGIATAN
|
|
public function createKegiatan()
|
|
{
|
|
// Ambil data users untuk dropdown pilihan pegawai (opsional)
|
|
$usersResponse = \Illuminate\Support\Facades\Http::withToken(session('api_token'))
|
|
->get($this->apiUrl('/users'));
|
|
|
|
$users = [];
|
|
if ($usersResponse->successful()) {
|
|
$allUsers = $usersResponse->json()['data'] ?? [];
|
|
// Hanya tampilkan user dengan role "user" (Pegawai/Petugas)
|
|
$users = array_filter($allUsers, function($u) {
|
|
return isset($u['role']) && strtolower($u['role']) === 'user';
|
|
});
|
|
}
|
|
|
|
return view('superadmin.kegiatan.create', compact('users'));
|
|
}
|
|
|
|
// 🔥 STORE KEGIATAN
|
|
public function storeKegiatan(Request $request)
|
|
{
|
|
$request->validate([
|
|
'nomor_surat' => 'required|string',
|
|
'kegiatan' => 'required|string',
|
|
'tanggal_mulai' => 'required|date',
|
|
'tanggal_selesai' => 'nullable|date',
|
|
'pegawai_ids' => 'required|array',
|
|
]);
|
|
|
|
$payload = [
|
|
'nomor_surat' => $request->nomor_surat,
|
|
'kegiatan' => $request->kegiatan,
|
|
'tanggal_mulai' => $request->tanggal_mulai,
|
|
'tanggal_selesai' => $request->tanggal_selesai,
|
|
'pegawai_ids' => $request->pegawai_ids,
|
|
];
|
|
|
|
$response = \Illuminate\Support\Facades\Http::withToken(session('api_token'))
|
|
->acceptJson()
|
|
->post($this->apiUrl('/penugasan'), $payload);
|
|
|
|
if ($response->successful()) {
|
|
return redirect()->route('admin.superadmin.dashboard')->with('success', 'Tugas baru berhasil dibuat');
|
|
}
|
|
|
|
if ($response->status() === 422) {
|
|
return back()->withErrors($response->json('errors'))->withInput();
|
|
}
|
|
|
|
return back()->with('error', 'Gagal membuat tugas baru: ' . $response->json('message', 'Error API'))->withInput();
|
|
}
|
|
|
|
|
|
|
|
public function export(Request $request)
|
|
{
|
|
$columns = $request->input('columns', []);
|
|
|
|
$response = \Illuminate\Support\Facades\Http::withToken(session('api_token'))
|
|
->get($this->apiUrl('/export-penugasan'), [
|
|
'columns' => $columns
|
|
]);
|
|
|
|
if ($response->successful()) {
|
|
$fileName = 'Laporan_Penugasan.xlsx';
|
|
$contentDisposition = $response->header('Content-Disposition');
|
|
|
|
if ($contentDisposition && preg_match('/filename="?([^"]+)"?/', $contentDisposition, $matches)) {
|
|
$fileName = $matches[1];
|
|
}
|
|
|
|
return response($response->body())
|
|
->header('Content-Type', $response->header('Content-Type') ?? 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
|
|
->header('Content-Disposition', 'attachment; filename="' . $fileName . '"');
|
|
}
|
|
|
|
return back()->with('error', 'Gagal mengunduh laporan: Endpoint backend mungkin bermasalah atau tidak tersedia.');
|
|
}
|
|
|
|
public function chartData(Request $request)
|
|
{
|
|
$mode = $request->get('mode', 'week');
|
|
$response = \Illuminate\Support\Facades\Http::withToken(session('api_token'))
|
|
->get($this->apiUrl('/penugasan'));
|
|
|
|
$items = collect([]);
|
|
if ($response->successful()) {
|
|
$items = collect($response->json()['data'])->filter(function($item) {
|
|
return $item['status'] !== 'dibatalkan';
|
|
})->map(function($item) {
|
|
return (object) ['created_at' => \Carbon\Carbon::parse($item['created_at'])];
|
|
});
|
|
}
|
|
$data = $this->buildChartData($items);
|
|
|
|
return response()->json([
|
|
'success' => true,
|
|
'data' => $data[$mode] ?? $data['week'],
|
|
]);
|
|
}
|
|
}
|