Compare commits
2 Commits
0d7a1faa44
...
21012d38c3
| Author | SHA1 | Date | |
|---|---|---|---|
| 21012d38c3 | |||
| de1216c5f5 |
@ -47,6 +47,7 @@ class AksesFileController extends Controller
|
||||
'pegawai_nama_entry' => auth()->user()?->dataUser?->namalengkap,
|
||||
'entry_at' => Carbon::now()->format('Y-m-d H:i:s.u'),
|
||||
'all_akses' => $data['akses'] === "all" ? true : false,
|
||||
'master_akses' => $data['master_akses'] === "yes" ? true : false,
|
||||
];
|
||||
$af = AksesFile::create($payload);
|
||||
if($data['akses'] === "unit"){
|
||||
@ -160,6 +161,7 @@ class AksesFileController extends Controller
|
||||
'pegawai_nama_modified' => auth()->user()?->dataUser?->namalengkap,
|
||||
'modified_at' => Carbon::now()->format('Y-m-d H:i:s.u'),
|
||||
'all_akses' => request('akses') === "all" ? true : false,
|
||||
'master_akses' => request('master_akses') === "yes" ? true : false,
|
||||
];
|
||||
$data->update($payload);
|
||||
|
||||
|
||||
@ -25,6 +25,7 @@ class DashboardController extends Controller
|
||||
public function index(){
|
||||
$katDok = MasterKategori::where('statusenabled', true)->select('master_kategori_directory_id', 'nama_kategori_directory')->get();
|
||||
$klasifikasiDok = MasterKlasifikasi::where('statusenabled', true)->select('master_klasifikasi_directory_id', 'nama_klasifikasi_directory')->get();
|
||||
$prefillFilter = session()->pull('dashboard_prefill');
|
||||
|
||||
$authMapping = auth()->user()?->dataUser?->mappingUnitKerjaPegawai[0];
|
||||
$authUnitKerja = $authMapping->objectunitkerjapegawaifk;
|
||||
@ -37,13 +38,37 @@ class DashboardController extends Controller
|
||||
'klasifikasiDok' => $klasifikasiDok,
|
||||
'authUnitKerja' => $authUnitKerja,
|
||||
'authSubUnitKerja' => $authSubUnitKerja,
|
||||
'allAkses' => $allAkses ?? null
|
||||
'allAkses' => $allAkses ?? null,
|
||||
'prefillFilter' => $prefillFilter
|
||||
];
|
||||
return view('dashboard.index', $payload);
|
||||
}
|
||||
|
||||
public function setDashboardPrefill(Request $request)
|
||||
{
|
||||
$payload = [
|
||||
'unitId' => (string) $request->input('unitId', ''),
|
||||
'subId' => (string) $request->input('subId', ''),
|
||||
'kategoriId' => (string) $request->input('kategoriId', ''),
|
||||
'unitName' => (string) $request->input('unitName', ''),
|
||||
'subName' => (string) $request->input('subName', ''),
|
||||
'kategoriName' => (string) $request->input('kategoriName', ''),
|
||||
];
|
||||
|
||||
session(['dashboard_prefill' => $payload]);
|
||||
|
||||
return response()->json([
|
||||
'status' => true,
|
||||
'message' => 'Prefill disimpan'
|
||||
]);
|
||||
}
|
||||
|
||||
public function dataUnitKerja(){
|
||||
$user = auth()->user()?->dataUser;
|
||||
$entryPegawaiId = auth()->user()?->objectpegawaifk;
|
||||
$authMapping = $user?->mappingUnitKerjaPegawai[0] ?? null;
|
||||
$authUnit = $authMapping?->objectunitkerjapegawaifk;
|
||||
$authSub = $authMapping?->objectsubunitkerjapegawaifk;
|
||||
$akses = AksesFile::where(['pegawai_id' => $user->id, 'statusenabled' => true])->first();
|
||||
$aksesAll = $akses?->akses ?? $akses?->all_akses ?? false;
|
||||
$detailUnitIds = collect();
|
||||
@ -62,6 +87,11 @@ class DashboardController extends Controller
|
||||
$allowedUnitIds = collect([$akses->unit_akses]);
|
||||
}
|
||||
}
|
||||
$limitPrivateToSubUnit = false;
|
||||
if (!$aksesAll && !$allowedUnitIds && $authUnit) {
|
||||
$allowedUnitIds = collect([$authUnit]);
|
||||
$limitPrivateToSubUnit = true;
|
||||
}
|
||||
|
||||
$kategori = request('kategori');
|
||||
$filterUnit = request('unitKerja');
|
||||
@ -71,37 +101,67 @@ class DashboardController extends Controller
|
||||
$katArray = $kategori ? explode(',', $kategori) : [];
|
||||
$katDok = MasterKategori::when($katArray, fn($q) => $q->whereIn('master_kategori_directory_id', $katArray))->where('statusenabled', true)->select('master_kategori_directory_id', 'nama_kategori_directory')->get();
|
||||
|
||||
$applyFileFilters = function ($q) use ($keyword, $katArray, $subArray, $entryPegawaiId) {
|
||||
$q->where(function($subQuery) use ($entryPegawaiId){
|
||||
$subQuery->where('status_action', '!=', 'rejected')
|
||||
->orWhere(function ($pending) use ($entryPegawaiId) {
|
||||
$pending->whereNull('status_action')
|
||||
->where('pegawai_id_entry', $entryPegawaiId);
|
||||
});
|
||||
})
|
||||
->when($subArray, fn($sq) => $sq->whereIn('id_sub_unit_kerja', $subArray))
|
||||
->when($katArray, fn($sq) => $sq->whereIn('master_kategori_directory_id', $katArray))
|
||||
->when($keyword, fn($sq) =>
|
||||
$sq->where(function ($query) use ($keyword) {
|
||||
$query->where('file', 'ilike', "%{$keyword}%");
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
$applyAccessFilter = function ($q) use ($aksesAll, $allowedUnitIds, $limitPrivateToSubUnit, $authSub) {
|
||||
if ($aksesAll) {
|
||||
return;
|
||||
}
|
||||
$hasPrivateScope = ($allowedUnitIds && $allowedUnitIds->isNotEmpty())
|
||||
|| ($limitPrivateToSubUnit && $authSub);
|
||||
$q->where(function ($query) use ($allowedUnitIds, $limitPrivateToSubUnit, $authSub, $hasPrivateScope) {
|
||||
$query->where('permission_file', true);
|
||||
if ($hasPrivateScope) {
|
||||
$query->orWhere(function ($sub) use ($allowedUnitIds, $limitPrivateToSubUnit, $authSub) {
|
||||
$sub->where('permission_file', false);
|
||||
if ($allowedUnitIds && $allowedUnitIds->isNotEmpty()) {
|
||||
$sub->whereIn('id_unit_kerja', $allowedUnitIds);
|
||||
}
|
||||
if ($limitPrivateToSubUnit && $authSub) {
|
||||
$sub->where('id_sub_unit_kerja', $authSub);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$applyFileQuery = function ($q) use ($applyFileFilters, $applyAccessFilter) {
|
||||
$applyFileFilters($q);
|
||||
$applyAccessFilter($q);
|
||||
};
|
||||
|
||||
if ($katArray && $filterUnit && $subArray) {
|
||||
/* mode pencarian lengkap */
|
||||
if ($allowedUnitIds && !$allowedUnitIds->contains((int) $filterUnit)) {
|
||||
$unitKerja = collect();
|
||||
} else {
|
||||
$unitKerja = UnitKerja::where('statusenabled', true)
|
||||
->where('id', $filterUnit)
|
||||
->with(['subUnitKerja' => fn($q) => $q->whereIn('id', $subArray)
|
||||
->with(['fileDirectory' => fn($q) => $q
|
||||
->where('id_unit_kerja', $filterUnit)
|
||||
->when($subArray, fn($q) => $q->whereIn('id_sub_unit_kerja', $subArray))
|
||||
->when($katArray, fn($q) => $q->whereIn('master_kategori_directory_id', $katArray))
|
||||
->when($keyword, fn($q) =>
|
||||
$q->where(function($query) use ($keyword) {
|
||||
$query->where('file', 'ilike', "%{$keyword}%")
|
||||
->orWhere('pegawai_nama_entry', 'ilike', "%{$keyword}%");
|
||||
})
|
||||
)
|
||||
])
|
||||
->whereHas('fileDirectory', fn($f) => $applyFileQuery($f))
|
||||
->with(['fileDirectory' => fn($f) => $applyFileQuery($f)])
|
||||
])
|
||||
->select('id', 'name')
|
||||
->get();
|
||||
}
|
||||
|
||||
} elseif ($aksesAll) {
|
||||
/* all akses */
|
||||
$unitKerja = UnitKerja::where('statusenabled', true)->with([ // muat relasi
|
||||
'subUnitKerja' => fn($q) => $q->with([ // sub-unit
|
||||
'fileDirectory' => fn($f) => $f->when($keyword, fn($q) =>
|
||||
'fileDirectory' => fn($f) => $f->whereNotNull('status_action')->when($keyword, fn($q) =>
|
||||
$q->where('file', 'ilike', "%{$keyword}%")
|
||||
->orWhere('pegawai_nama_entry', 'ilike', "%{$keyword}%")
|
||||
)
|
||||
])
|
||||
])
|
||||
@ -109,38 +169,37 @@ class DashboardController extends Controller
|
||||
->get();
|
||||
|
||||
} elseif ($allowedUnitIds) {
|
||||
/* akses per unit (single/multiple) */
|
||||
$unitKerja = UnitKerja::where('statusenabled', true)
|
||||
->whereIn('id', $allowedUnitIds)
|
||||
->with([ // muat relasi
|
||||
'subUnitKerja' => fn($q) => $q->with([ // sub-unit
|
||||
'fileDirectory' => fn($f) => $f->when($keyword, fn($q) =>
|
||||
$q->where(function($query) use ($keyword) {
|
||||
$query->where('file', 'ilike', "%{$keyword}%")
|
||||
->orWhere('pegawai_nama_entry', 'ilike', "%{$keyword}%");
|
||||
})
|
||||
)
|
||||
])
|
||||
->where(function ($q) use ($allowedUnitIds, $applyFileQuery) {
|
||||
if ($allowedUnitIds && $allowedUnitIds->isNotEmpty()) {
|
||||
$q->whereIn('id', $allowedUnitIds);
|
||||
}
|
||||
$q->orWhereHas('subUnitKerja.fileDirectory', fn($f) => $applyFileQuery($f));
|
||||
})
|
||||
->with([
|
||||
'subUnitKerja' => fn($q) => $q->whereHas('fileDirectory', fn($f) => $applyFileQuery($f))
|
||||
->with(['fileDirectory' => fn($f) => $applyFileQuery($f)])
|
||||
])
|
||||
->select('id', 'name')
|
||||
->get();
|
||||
|
||||
} else {
|
||||
/* default : unit & sub milik sendiri */
|
||||
$authUnit = $user?->mappingUnitKerjaPegawai[0]?->objectunitkerjapegawaifk;
|
||||
$authSub = $user?->mappingUnitKerjaPegawai[0]?->objectsubunitkerjapegawaifk;
|
||||
|
||||
$unitKerja = UnitKerja::where('statusenabled', true)
|
||||
->where('id', $authUnit)
|
||||
->where(function ($q) use ($authUnit, $applyFileQuery) {
|
||||
if ($authUnit) {
|
||||
$q->where('id', $authUnit);
|
||||
}
|
||||
$q->orWhereHas('subUnitKerja.fileDirectory', fn($f) => $applyFileQuery($f));
|
||||
})
|
||||
->with([ // 1. sub-unit milik user
|
||||
'subUnitKerja' => fn($q) => $q->where('id', $authSub)
|
||||
'subUnitKerja' => fn($q) => $q->where(function ($sq) use ($authSub, $applyFileQuery) {
|
||||
if ($authSub) {
|
||||
$sq->where('id', $authSub);
|
||||
}
|
||||
$sq->orWhereHas('fileDirectory', fn($f) => $applyFileQuery($f));
|
||||
})
|
||||
->with([ // 2. file-directory + filter keyword
|
||||
'fileDirectory' => fn($f) => $f->when($keyword, fn($q) =>
|
||||
$q->where(function($query) use ($keyword) {
|
||||
$query->where('file', 'ilike', "%{$keyword}%")
|
||||
->orWhere('pegawai_nama_entry', 'ilike', "%{$keyword}%");
|
||||
})
|
||||
)
|
||||
'fileDirectory' => fn($f) => $applyFileQuery($f)
|
||||
])
|
||||
])
|
||||
->select('id', 'name')
|
||||
@ -302,7 +361,7 @@ class DashboardController extends Controller
|
||||
$paths = [];
|
||||
foreach ($rows as $r) {
|
||||
if(!empty($r['sub_unit_id'])){
|
||||
$files = FileDirectory::where('id_sub_unit_kerja', $r['sub_unit_id'])->where('statusenabled', true)->pluck('file');
|
||||
$files = FileDirectory::where('id_sub_unit_kerja', $r['sub_unit_id'])->where('statusenabled', true)->where('status_action', 'approved')->pluck('file');
|
||||
|
||||
$paths = array_merge($paths, $files->toArray());
|
||||
}
|
||||
@ -347,9 +406,9 @@ class DashboardController extends Controller
|
||||
$type = request('type');
|
||||
|
||||
if($type === "unit"){
|
||||
$data = FileDirectory::where('id_unit_kerja', $id)->where('statusenabled', true)->pluck('file');
|
||||
$data = FileDirectory::where('id_unit_kerja', $id)->where('statusenabled', true)->where('status_action', 'approved')->pluck('file');
|
||||
}else{
|
||||
$data = FileDirectory::where('id_sub_unit_kerja', $id)->where('statusenabled', true)->pluck('file');
|
||||
$data = FileDirectory::where('id_sub_unit_kerja', $id)->where('statusenabled', true)->where('status_action', 'approved')->pluck('file');
|
||||
}
|
||||
if (empty($data)) {
|
||||
return response()->json(['message' => 'File tidak ditemukan'], 404);
|
||||
@ -400,11 +459,18 @@ class DashboardController extends Controller
|
||||
$perPage = (int) request('per_page', 10);
|
||||
$authUnitId = auth()->user()->dataUser?->mappingUnitKerjaPegawai[0]?->objectunitkerjapegawaifk;
|
||||
$user = auth()->user()?->dataUser;
|
||||
$entryPegawaiId = auth()->user()?->objectpegawaifk;
|
||||
$akses = AksesFile::where(['pegawai_id' => $user->id, 'statusenabled' => true])->first();
|
||||
$keyword = request('keyword');
|
||||
|
||||
$query = FileDirectory::where('statusenabled', true)
|
||||
->when($keyword, function ($q) use ($keyword) {
|
||||
->where(function($subQuery) use ($entryPegawaiId){
|
||||
$subQuery->where('status_action', '!=', 'rejected')
|
||||
->orWhere(function ($pending) use ($entryPegawaiId) {
|
||||
$pending->whereNull('status_action')
|
||||
->where('pegawai_id_entry', $entryPegawaiId);
|
||||
});
|
||||
})->when($keyword, function ($q) use ($keyword) {
|
||||
$q->where(function ($sub) use ($keyword) {
|
||||
$sub->where('file', 'ILIKE', "%{$keyword}%")
|
||||
->orWhere('no_dokumen', 'ILIKE', "%{$keyword}%");
|
||||
@ -674,8 +740,8 @@ class DashboardController extends Controller
|
||||
$perPage = (int) request('per_page', 10);
|
||||
$page = max(1, (int) request('page', 1));
|
||||
$keyword = strtolower(request('keyword', ''));
|
||||
|
||||
$rows = FileDirectory::where('statusenabled', true)->pluck('file');
|
||||
$authUnit = auth()->user()->masterPersetujuan->details->pluck('unit_pegawai_id')->unique()->toArray();
|
||||
$rows = FileDirectory::where('statusenabled', true)->whereNotNull('status_action')->whereIn('id_unit_kerja', $authUnit)->pluck('file');
|
||||
|
||||
$grouped = [];
|
||||
foreach ($rows as $path) {
|
||||
@ -754,8 +820,12 @@ class DashboardController extends Controller
|
||||
$keyword = request('keyword');
|
||||
$start = request('start_date');
|
||||
$end = request('end_date');
|
||||
$authUnit = auth()->user()->masterPersetujuan->details->pluck('unit_pegawai_id')->unique()->toArray();
|
||||
|
||||
$query = FileDirectory::where('statusenabled', true)->whereNull('status_action')->orderBy('entry_at','desc');
|
||||
$query = FileDirectory::where('statusenabled', true)->where(function($q){
|
||||
$q->where('status_action', '!=', 'approved')
|
||||
->orWhereNull('status_action');
|
||||
})->whereIn('id_unit_kerja', $authUnit)->orderBy('entry_at','desc');
|
||||
if($keyword){
|
||||
$query->where(function($q) use ($keyword){
|
||||
$q->where('file', 'ILIKE', "%{$keyword}%")
|
||||
@ -783,6 +853,7 @@ class DashboardController extends Controller
|
||||
'entry_at' => $item->entry_at,
|
||||
'tanggal_terbit' => $item->tanggal_terbit,
|
||||
'permission_file' => $item->permission_file,
|
||||
'status_action' => $item->status_action
|
||||
];
|
||||
});
|
||||
return response()->json([
|
||||
@ -886,9 +957,10 @@ class DashboardController extends Controller
|
||||
|
||||
public function countDataPending(){
|
||||
try {
|
||||
$count = FileDirectory::where('statusenabled', true)
|
||||
->whereNull('status_action')
|
||||
->count();
|
||||
$query = FileDirectory::where('statusenabled', true)
|
||||
->whereNull('status_action');
|
||||
$authUnit = auth()->user()->masterPersetujuan->details->pluck('unit_pegawai_id')->unique()->toArray();
|
||||
$count= $query->whereIn('id_unit_kerja', $authUnit)->count();
|
||||
return response()->json([
|
||||
'status' => true,
|
||||
'count' => $count,
|
||||
|
||||
@ -22,7 +22,12 @@ class LogActivityController extends Controller
|
||||
|
||||
$query = LogActivity::query()
|
||||
->orderBy('entry_at','desc');
|
||||
|
||||
if(auth()->user()->masterPersetujuan){
|
||||
$authUnit = auth()->user()->masterPersetujuan->details->pluck('unit_pegawai_id')->unique()->toArray();
|
||||
$query = $query->whereIn('id_unit_kerja', $authUnit);
|
||||
}else{
|
||||
$query = $query->where('pegawai_id_entry', auth()->user()->objectpegawaifk);
|
||||
}
|
||||
if($keyword){
|
||||
$query->where(function($q) use ($keyword){
|
||||
$q->where('pegawai_nama_entry', 'ILIKE', "%{$keyword}%")
|
||||
|
||||
22
app/Http/Middleware/EnsureMasterAkses.php
Normal file
22
app/Http/Middleware/EnsureMasterAkses.php
Normal file
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class EnsureMasterAkses
|
||||
{
|
||||
public function handle(Request $request, Closure $next): Response
|
||||
{
|
||||
$user = $request->user();
|
||||
$hasAccess = $user && $user->akses && $user->akses->master_akses;
|
||||
|
||||
if (!$hasAccess) {
|
||||
abort(403, 'Tidak memiliki akses.');
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
}
|
||||
22
app/Http/Middleware/EnsureMasterPersetujuan.php
Normal file
22
app/Http/Middleware/EnsureMasterPersetujuan.php
Normal file
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class EnsureMasterPersetujuan
|
||||
{
|
||||
public function handle(Request $request, Closure $next): Response
|
||||
{
|
||||
$user = $request->user();
|
||||
$hasAccess = $user && $user->masterPersetujuan;
|
||||
|
||||
if (!$hasAccess) {
|
||||
abort(403, 'Tidak memiliki akses.');
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
}
|
||||
@ -45,8 +45,16 @@ class User extends Authenticatable
|
||||
'katasandi' => 'hashed',
|
||||
];
|
||||
}
|
||||
protected $with = ['dataUser'];
|
||||
protected $with = ['dataUser', 'masterPersetujuan', 'akses'];
|
||||
public function dataUser(){
|
||||
return $this->belongsTo(DataUser::class, 'objectpegawaifk', 'id')->select('id', 'namalengkap');
|
||||
}
|
||||
|
||||
public function masterPersetujuan(){
|
||||
return $this->belongsTo(masterPersetujuan::class, 'objectpegawaifk', 'pegawai_id')->where('statusenabled', true)->with('details');
|
||||
}
|
||||
|
||||
public function akses(){
|
||||
return $this->belongsTo(AksesFile::class, 'objectpegawaifk', 'pegawai_id')->where('statusenabled', true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -11,7 +11,10 @@ return Application::configure(basePath: dirname(__DIR__))
|
||||
health: '/up',
|
||||
)
|
||||
->withMiddleware(function (Middleware $middleware): void {
|
||||
//
|
||||
$middleware->alias([
|
||||
'akses.master' => \App\Http\Middleware\EnsureMasterAkses::class,
|
||||
'master.persetujuan' => \App\Http\Middleware\EnsureMasterPersetujuan::class,
|
||||
]);
|
||||
})
|
||||
->withExceptions(function (Exceptions $exceptions): void {
|
||||
//
|
||||
|
||||
5
public/assets/css/styles.min.css
vendored
5
public/assets/css/styles.min.css
vendored
@ -15647,7 +15647,7 @@ textarea.form-control-lg {
|
||||
.left-sidebar .scroll-sidebar {
|
||||
overflow-y: auto;
|
||||
padding: 0 24px;
|
||||
height: calc(100vh - 310px);
|
||||
height: calc(100vh - 120px);
|
||||
border-radius: 7px;
|
||||
}
|
||||
.left-sidebar .scroll-sidebar .simplebar-track.simplebar-horizontal {
|
||||
@ -15818,11 +15818,10 @@ textarea.form-control-lg {
|
||||
width: 100%;
|
||||
background: var(--bs-body-bg);
|
||||
padding: 0 10px;
|
||||
/* top: 65px; */
|
||||
}
|
||||
@media (max-width: 991.98px) {
|
||||
.app-header {
|
||||
top: 131px;
|
||||
top: 0px;
|
||||
}
|
||||
}
|
||||
.app-header .container-fluid, .app-header .container-sm, .app-header .container-md, .app-header .container-lg, .app-header .container-xl, .app-header .container-xxl {
|
||||
|
||||
@ -105,7 +105,7 @@ function editAkses(e){
|
||||
formEditAkses.attr('action', `/akses/${data.akses_file_id}`)
|
||||
$("#unit_akses_edit").empty().trigger('change');
|
||||
$("#unit_akses_wrapper_edit").addClass('d-none');
|
||||
|
||||
$("#master_akses_edit").prop("checked", data.master_akses == 1)
|
||||
selectOptionPegawaiEdit()
|
||||
selectOptionUnitKerjaEdit()
|
||||
if (data.pegawai_id) {
|
||||
|
||||
@ -18,6 +18,8 @@
|
||||
{
|
||||
title:"Action",
|
||||
formatter: function(value, row){
|
||||
console.log(row);
|
||||
|
||||
let buttons = '';
|
||||
buttons += `
|
||||
<button class="btn btn-sm btn-danger me-2" onclick="deleteAkses(this)"
|
||||
@ -31,7 +33,9 @@
|
||||
data-pegawai_id="${row?.pegawai_id}"
|
||||
data-pegawai_nama="${row?.pegawai?.namalengkap}"
|
||||
data-unit_id="${row?.unit_akses}"
|
||||
data-unit_nama="${row?.akses?.name}">
|
||||
data-unit_nama="${row?.akses?.name}"
|
||||
data-master_akses="${row?.master_akses ? 1 : 0}"
|
||||
>
|
||||
<i class="fa-solid fa-pencil"></i>
|
||||
</button>`
|
||||
return `
|
||||
|
||||
@ -107,8 +107,14 @@ function addForm(){
|
||||
By Unit Akses
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox"
|
||||
name="data[${colCount}][master_akses]" id="akses_unit_${colCount}" value="yes">
|
||||
<label class="form-check-label">
|
||||
Akses Master
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<small class="text-muted">Pilih salah satu.</small>
|
||||
</div>
|
||||
<div class="col-md-4 mb-2 d-none" id="unit_akses_wrapper_${colCount}">
|
||||
<label>Unit Kerja</label>
|
||||
|
||||
@ -47,11 +47,16 @@ $(document).ready(function() {
|
||||
loadSubUnitKerja(initialUnit);
|
||||
}
|
||||
|
||||
let prefillSubIds = [];
|
||||
let prefillSubMeta = {};
|
||||
|
||||
// jalankan setiap kali unit_kerja berubah
|
||||
$('.unit_kerja').on('change', function(){
|
||||
let idUnit = $(this).val();
|
||||
if(idUnit){
|
||||
loadSubUnitKerja(idUnit);
|
||||
loadSubUnitKerja(idUnit, prefillSubIds, prefillSubMeta);
|
||||
prefillSubIds = [];
|
||||
prefillSubMeta = {};
|
||||
}
|
||||
});
|
||||
|
||||
@ -62,9 +67,67 @@ $(document).ready(function() {
|
||||
}else{
|
||||
selectOptionUnitKerjaV2(0);
|
||||
}
|
||||
|
||||
if (window.__folderPrefillApplied) return;
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
const prefill = window.__prefillFromSession || null;
|
||||
|
||||
const unitId = prefill?.unitId || urlParams.get('unitKerja');
|
||||
const subParam = prefill?.subId || urlParams.get('subUnit');
|
||||
const katParam = prefill?.kategoriId || urlParams.get('kategori');
|
||||
const unitName = prefill?.unitName || urlParams.get('unitName');
|
||||
const subName = prefill?.subName || urlParams.get('subName');
|
||||
const kategoriName = prefill?.kategoriName || urlParams.get('kategoriName');
|
||||
|
||||
let prefillSubIdsFinal = [];
|
||||
let prefillKatIdsFinal = [];
|
||||
|
||||
if (unitId) {
|
||||
window.__folderPrefillApplied = true;
|
||||
window.__prefillFromSession = null;
|
||||
$('.unit_kerja').val(null).trigger('change');
|
||||
$('.sub_unit_kerja').val(null).trigger('change');
|
||||
$('.kategori_dok').val(null).trigger('change');
|
||||
|
||||
const unitLabel = unitName || unitId;
|
||||
const unitOption = new Option(unitLabel, unitId, true, true);
|
||||
const selectedSubIds = subParam ? Array.from(new Set(subParam.split(',').filter(Boolean))) : [];
|
||||
const subNames = subName ? subName.split(',').map(s => s.trim()).filter(Boolean) : [];
|
||||
|
||||
prefillSubIds = selectedSubIds;
|
||||
prefillSubMeta = selectedSubIds.reduce((acc, id, idx) => {
|
||||
let label = subNames[idx] || subNames[0] || id;
|
||||
label = label.replace(/^\d+\s*\/\s*/, '');
|
||||
acc[id] = label;
|
||||
return acc;
|
||||
}, {});
|
||||
$('.unit_kerja').append(unitOption).trigger('change');
|
||||
|
||||
if (selectedSubIds.length) {
|
||||
$('.sub_unit_kerja').val(selectedSubIds).trigger('change');
|
||||
}
|
||||
|
||||
prefillSubIdsFinal = selectedSubIds;
|
||||
}
|
||||
|
||||
if (katParam) {
|
||||
const katIds = Array.from(new Set(katParam.split(',').filter(Boolean)));
|
||||
if (katIds.length) {
|
||||
$('.kategori_dok').val(katIds).trigger('change');
|
||||
prefillKatIdsFinal = katIds;
|
||||
} else if (kategoriName) {
|
||||
const katOption = new Option(kategoriName, katParam, true, true);
|
||||
$('.kategori_dok').append(katOption).trigger('change');
|
||||
prefillKatIdsFinal = katParam ? [katParam] : [];
|
||||
}
|
||||
}
|
||||
|
||||
if ((unitId || subParam || katParam) && typeof index === 'function') {
|
||||
index(prefillKatIdsFinal, unitId, prefillSubIdsFinal, '');
|
||||
}
|
||||
});
|
||||
|
||||
function loadSubUnitKerja(unitId){
|
||||
function loadSubUnitKerja(unitId, selectedSubIds = [], selectedSubMeta = {}){
|
||||
$('.sub_unit_kerja').empty().append('<option value="" disabled>-- Pilih Sub Unit Kerja --</option>');
|
||||
|
||||
$.ajax({
|
||||
@ -73,10 +136,24 @@ function loadSubUnitKerja(unitId){
|
||||
success: function(response) {
|
||||
if (response?.data) {
|
||||
response.data.forEach(unit => {
|
||||
let selected = (authSubUnitKerja && unit.id === authSubUnitKerja.objectsubunitkerjapegawaifk);
|
||||
let selected = false;
|
||||
if (selectedSubIds.length) {
|
||||
selected = selectedSubIds.includes(String(unit.id));
|
||||
} else if (authSubUnitKerja) {
|
||||
selected = unit.id === authSubUnitKerja.objectsubunitkerjapegawaifk;
|
||||
}
|
||||
const option = new Option(unit.name, unit.id, false, selected);
|
||||
$('.sub_unit_kerja').append(option);
|
||||
});
|
||||
if (selectedSubIds.length) {
|
||||
selectedSubIds.forEach(id => {
|
||||
if ($(`.sub_unit_kerja option[value="${id}"]`).length === 0) {
|
||||
const label = selectedSubMeta[id] || id;
|
||||
const opt = new Option(label, id, false, true);
|
||||
$('.sub_unit_kerja').append(opt);
|
||||
}
|
||||
});
|
||||
}
|
||||
$('.sub_unit_kerja').trigger('change');
|
||||
}
|
||||
}
|
||||
@ -321,4 +398,3 @@ function selectOptionUnitKerjaV2(colCount) {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -10,9 +10,18 @@ function renderTree(units, katDok, keyword) {
|
||||
<li class="file-tree-li folder">
|
||||
<input class="form-check-input" type="checkbox" data-select="unit" data-unit_id="${el?.id}">
|
||||
<span class="fw-bolder">📂 ${el.name}</span>
|
||||
<button type="button" class="btn btn-primary btn-sm" onclick="download(this)" data-part="unit" data-id="${el?.id}">
|
||||
<i class="fa-solid fa-download"></i>
|
||||
</button>
|
||||
<div class="dropdown d-inline ms-1">
|
||||
<button type="button" class="btn btn-sm btn-link text-decoration-none folder-menu-icon dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false" aria-label="Menu folder">
|
||||
<i class="fa-solid fa-ellipsis-vertical"></i>
|
||||
</button>
|
||||
<ul class="dropdown-menu">
|
||||
<li>
|
||||
<button type="button" class="dropdown-item folder-download" data-part="unit" data-id="${el?.id}">
|
||||
<i class="fa-solid fa-download me-2"></i>Download
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
${Array.isArray(el.sub_unit_kerja) && el.sub_unit_kerja.length > 0 ? `
|
||||
<ul class="file-tree-ul mt-1 ms-2">
|
||||
@ -21,9 +30,18 @@ function renderTree(units, katDok, keyword) {
|
||||
\
|
||||
<input class="form-check-input" type="checkbox" data-select="sub_unit" data-unit_id="${el.id}" data-sub_unit_id="${sub?.id}" >
|
||||
<span class="fw-semibold">📂 ${sub.name}</span>
|
||||
<button type="button" class="btn btn-outline-primary btn-sm ms-auto" onclick="download(this)" data-part="sub_unit" data-id="${sub?.id}">
|
||||
<i class="fa-solid fa-download"></i>
|
||||
</button>
|
||||
<div class="dropdown d-inline ms-1">
|
||||
<button type="button" class="btn btn-sm btn-link text-decoration-none folder-menu-icon dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false" aria-label="Menu folder">
|
||||
<i class="fa-solid fa-ellipsis-vertical"></i>
|
||||
</button>
|
||||
<ul class="dropdown-menu">
|
||||
<li>
|
||||
<button type="button" class="dropdown-item folder-download" data-part="sub_unit" data-id="${sub?.id}">
|
||||
<i class="fa-solid fa-download me-2"></i>Download
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
${Array.isArray(katDok) && katDok.length > 0 ? `
|
||||
<ul class="file-tree-ul ms-2">
|
||||
@ -41,20 +59,33 @@ function renderTree(units, katDok, keyword) {
|
||||
${files.map(file => {
|
||||
let fileName = file.file.split('/').pop();
|
||||
const isPublic = String(file.permission_file).toLowerCase() === 'true' || file.permission_file === 1 || file.permission_file === '1';
|
||||
console.log(file);
|
||||
let statusLabel = '';
|
||||
let statusClass = '';
|
||||
|
||||
if (!file.status_action) {
|
||||
statusLabel = 'Pending';
|
||||
statusClass = 'bg-warning text-dark';
|
||||
} else if (isPublic) {
|
||||
statusLabel = 'Umum';
|
||||
statusClass = 'bg-success';
|
||||
} else {
|
||||
statusLabel = 'Internal Unit';
|
||||
statusClass = 'bg-secondary';
|
||||
}
|
||||
return `
|
||||
<li class="file-tree-li">
|
||||
<div class="d-flex align-items-center gap-2 flex-wrap">
|
||||
<span>📄</span>
|
||||
<a href="#" class="file-link"
|
||||
<a href="#" class="file-link ${!file?.status_action ? 'fst-italic' :''}"
|
||||
data-file="${file?.file}"
|
||||
data-fileName="${fileName || '-'}"
|
||||
data-id="${file.file_directory_id}"
|
||||
data-no_dokumen="${file.no_dokumen || '-'}"
|
||||
data-tanggal_terbit="${file.tanggal_terbit || '-'}"
|
||||
data-permission_file="${file.permission_file || '-'}">${fileName}</a>
|
||||
<span class="badge ${isPublic ? 'bg-success' : 'bg-secondary'}">
|
||||
${isPublic ? 'Umum' : 'Internal'}
|
||||
<span class="badge ${statusClass}">
|
||||
${statusLabel}
|
||||
</span>
|
||||
</div>
|
||||
</li>
|
||||
@ -94,6 +125,7 @@ function index(kategori_dok = [], unitKerja = null, subUnitKerja = [], keyword =
|
||||
if (Array.isArray(data?.data?.unitKerja)) {
|
||||
file_tree.innerHTML = renderTree(data.data.unitKerja, data.data.katDok, keyword);
|
||||
|
||||
// Toggle buka/tutup folder
|
||||
// Toggle buka/tutup folder
|
||||
file_tree.querySelectorAll(".folder > span").forEach(span => {
|
||||
span.addEventListener("click", () => {
|
||||
@ -108,6 +140,7 @@ function index(kategori_dok = [], unitKerja = null, subUnitKerja = [], keyword =
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
} else {
|
||||
file_tree.innerHTML = `
|
||||
<p style="color: primary">
|
||||
@ -120,7 +153,19 @@ function index(kategori_dok = [], unitKerja = null, subUnitKerja = [], keyword =
|
||||
}
|
||||
|
||||
|
||||
index();
|
||||
const initialParams = new URLSearchParams(window.location.search);
|
||||
const initialUnit = initialParams.get('unitKerja');
|
||||
const initialSub = initialParams.get('subUnit');
|
||||
const initialKat = initialParams.get('kategori');
|
||||
const initialKeyword = initialParams.get('keyword');
|
||||
const initialSubArr = initialSub ? initialSub.split(',').filter(Boolean) : [];
|
||||
const initialKatArr = initialKat ? initialKat.split(',').filter(Boolean) : [];
|
||||
|
||||
if (initialUnit || initialSubArr.length || initialKatArr.length || initialKeyword) {
|
||||
index(initialKatArr, initialUnit, initialSubArr, initialKeyword || '');
|
||||
} else {
|
||||
index();
|
||||
}
|
||||
|
||||
function referesh(){
|
||||
index()
|
||||
@ -143,14 +188,16 @@ function searchData(){
|
||||
return
|
||||
}
|
||||
|
||||
index(kategori_dok, unitKerja, subUnitKerja, [], keyword);
|
||||
index(kategori_dok, unitKerja, subUnitKerja, keyword);
|
||||
}
|
||||
|
||||
let debounceTimer;
|
||||
function debounceSearch(input) {
|
||||
function debounceSearch(value) {
|
||||
console.log(value);
|
||||
|
||||
clearTimeout(debounceTimer);
|
||||
debounceTimer = setTimeout(() => {
|
||||
searchFile(input.value.trim());
|
||||
searchFile(value.trim());
|
||||
}, 300);
|
||||
}
|
||||
|
||||
@ -159,7 +206,8 @@ function searchFile(keyword){
|
||||
let kategori_dok = $("#kategori_dok").val()
|
||||
let unitKerja = $("#unit_kerja").val()
|
||||
let subUnitKerja = $("#sub_unit_kerja").val()
|
||||
index(kategori_dok, unitKerja, subUnitKerja, [], keyword);
|
||||
|
||||
index(kategori_dok, unitKerja, subUnitKerja, keyword);
|
||||
}
|
||||
|
||||
|
||||
@ -277,3 +325,10 @@ function downloadMultiple(){
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
// Klik menu download dari ikon ⋮
|
||||
document.addEventListener('click', function (e) {
|
||||
const btn = e.target.closest('.folder-download');
|
||||
if (!btn) return;
|
||||
download(btn);
|
||||
});
|
||||
|
||||
@ -77,13 +77,13 @@ function addForm(){
|
||||
</select>
|
||||
<small class="text-muted">Cari nama pegawai.</small>
|
||||
</div>
|
||||
<div class="col-md-8 mb-2" id="unit_akses_wrapper_${colCount}">
|
||||
<div class="col-md-7 mb-2" id="unit_akses_wrapper_${colCount}">
|
||||
<label>Unit Kerja</label>
|
||||
<select class="form-control" name="data[${colCount}][unit_akses][]" id="unit_akses_${colCount}" multiple>
|
||||
</select>
|
||||
<small class="text-muted">Bisa pilih lebih dari satu.</small>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<div class="col-md-1">
|
||||
<button type="button" class="btn btn-danger mt-3 me-2" onclick="removeCol(${colCount})"><i class="fa-solid fa-trash"></i></button>
|
||||
</div>
|
||||
|
||||
|
||||
@ -54,8 +54,13 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
`;
|
||||
return `
|
||||
<tr>
|
||||
<td>${aksi}</td>
|
||||
<td>${item?.status_action !== "rejected" ? aksi : ''}</td>
|
||||
<td>${item.no_dokumen || '-'}</td>
|
||||
<td>
|
||||
<button class="btn btn-sm ${item?.status_action !== "rejected" ? 'btn-warning' : 'btn-danger'} btn-warning ">
|
||||
${item?.status_action !== "rejected" ? 'Pending' : 'Rejected'}
|
||||
</button>
|
||||
</td>
|
||||
<td><a href="#" class="file-link"
|
||||
data-file="${item.file}"
|
||||
data-fileName="${item.fileName}"
|
||||
@ -115,7 +120,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
if (pageData.length === 0) {
|
||||
tbody.innerHTML = `
|
||||
<tr>
|
||||
<td colspan="4" class="text-center text-muted py-4">
|
||||
<td colspan="7" class="text-center text-muted py-4">
|
||||
Tidak ada data
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@ -24,7 +24,7 @@
|
||||
<div class="col-12 col-md-4">
|
||||
<label class="form-label mb-1 d-block">Akses</label>
|
||||
|
||||
<div class="d-flex flex-wrap gap-3">
|
||||
<div class="d-flex flex-wrap gap-2">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio"
|
||||
name="data[0][akses]" id="akses_all_0" value="all" checked
|
||||
@ -42,9 +42,15 @@
|
||||
By Unit Akses
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<small class="text-muted">Pilih salah satu.</small>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox"
|
||||
name="data[0][master_akses]" id="akses_unit_0" value="yes">
|
||||
<label class="form-check-label" for="akses_unit_0">
|
||||
Akses Master
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4 mb-2 d-none" id="unit_akses_wrapper_0">
|
||||
<label class="form-label">Unit Kerja</label>
|
||||
|
||||
@ -24,7 +24,7 @@
|
||||
</div>
|
||||
<div class="col-12 col-md-2">
|
||||
<label class="form-label mb-1 d-block">Akses</label>
|
||||
<div class="d-flex flex-wrap gap-3">
|
||||
<div class="d-flex flex-wrap gap-2">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio"
|
||||
name="akses" id="akses_all_edit" value="all"
|
||||
@ -41,8 +41,15 @@
|
||||
By Unit Akses
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox"
|
||||
name="master_akses" id="master_akses_edit" value="yes">
|
||||
<label class="form-check-label">
|
||||
Akses Master
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<small class="text-muted">Pilih salah satu.</small>
|
||||
|
||||
</div>
|
||||
<div class="col-12 col-md-6 d-none" id="unit_akses_wrapper_edit">
|
||||
<label class="form-label">Unit Kerja</label>
|
||||
|
||||
@ -42,6 +42,22 @@
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.folder-menu-icon {
|
||||
cursor: pointer;
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
padding: 0 4px;
|
||||
}
|
||||
|
||||
.file-tree-li.folder:hover .folder-menu-icon {
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.folder-menu-icon.dropdown-toggle::after {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.collapsed > .file-tree-ul {
|
||||
display: none;
|
||||
}
|
||||
@ -122,19 +138,18 @@
|
||||
</button>
|
||||
<div class="input-group input-group-sm" style="max-width:260px;">
|
||||
<span class="input-group-text bg-white"><i class="fa fa-search text-muted"></i></span>
|
||||
<input type="text" id="search_file" oninput="debounceSearch(this)" class="form-control" placeholder="Cari nama/no dokumen">
|
||||
<input type="text" id="search_file" oninput="debounceSearch(this.value)" class="form-control" placeholder="Cari nama/no dokumen">
|
||||
</div>
|
||||
<div class="d-flex align-items-center gap-2 ms-auto">
|
||||
<span class="badge bg-success">Umum</span>
|
||||
<span class="badge bg-secondary">Internal</span>
|
||||
</div>
|
||||
</div>
|
||||
<div id="file_tree"></div>
|
||||
<div id="file_tree" style="max-height: 60vh; overflow-y:auto;"></div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -147,6 +162,7 @@
|
||||
const allAkses = @json($allAkses);
|
||||
const authUnitKerja = @json(auth()->user()->dataUser?->mappingUnitKerjaPegawai[0]?->unitKerja);
|
||||
const authSubUnitKerja = @json(auth()->user()->dataUser?->mappingUnitKerjaPegawai[0]);
|
||||
window.__prefillFromSession = @json($prefillFilter ?? null);
|
||||
function isPublic(permissionVal){
|
||||
if(permissionVal === null || permissionVal === undefined) return false;
|
||||
const val = String(permissionVal).toLowerCase();
|
||||
@ -266,10 +282,6 @@
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<script src="{{ ver('/js/dashboard/_init.js') }}"></script>
|
||||
|
||||
@ -1,4 +1,41 @@
|
||||
@extends('layout.main')
|
||||
<style>
|
||||
.table-fixed{ table-layout: fixed; width: 100%; }
|
||||
.table-fixed th:nth-child(1), .table-fixed td:nth-child(1){ width: 140px; }
|
||||
.table-fixed th:nth-child(2), .table-fixed td:nth-child(2){ width: 260px; }
|
||||
.table-fixed th:nth-child(3), .table-fixed td:nth-child(3){ width: 220px; }
|
||||
.table-fixed th:nth-child(4), .table-fixed td:nth-child(4){ width: 120px; }
|
||||
.table-fixed th:nth-child(5), .table-fixed td:nth-child(5){ width: 150px; }
|
||||
|
||||
.file-cell{
|
||||
white-space: normal;
|
||||
word-break: break-word;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
.folder-cell{
|
||||
max-width: 220px;
|
||||
}
|
||||
|
||||
.folder-badge{
|
||||
white-space: normal !important;
|
||||
word-break: break-word;
|
||||
overflow-wrap: anywhere;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
max-width: 100%;
|
||||
text-align: left;
|
||||
line-height: 1.3;
|
||||
padding: .35rem .5rem;
|
||||
}
|
||||
|
||||
.folder-link-sm{
|
||||
font-size: 13px;
|
||||
text-decoration: underline;
|
||||
}
|
||||
</style>
|
||||
@section('body_main')
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
@ -30,8 +67,8 @@
|
||||
</div>
|
||||
<div class="small text-muted ms-md-auto" id="tableSummary">Memuat data...</div>
|
||||
</div>
|
||||
<div class="table-responsive" style="max-height: 100vh; overflow-y:auto;">
|
||||
<table class="table table-sm table-hover align-middle mb-0" id="lastUpdatedTable">
|
||||
<div class="table-responsive" style="max-height: 70vh; overflow-y:auto;">
|
||||
<table class="table table-sm table-hover align-middle mb-0 table-fixed" id="lastUpdatedTable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Nomor Surat</th>
|
||||
@ -100,12 +137,29 @@
|
||||
const fileName = parts.pop() || '-';
|
||||
const folderPath = parts.join('/') || '-';
|
||||
const publicDoc = isPublic(item.permission_file);
|
||||
const unitName = parts[0] || '';
|
||||
const subName = parts[1] || '';
|
||||
const kategoriName = parts[2] || '';
|
||||
let statusLabel = '';
|
||||
let statusClass = '';
|
||||
|
||||
if (!item.status_action) {
|
||||
statusLabel = 'Pending';
|
||||
statusClass = 'bg-warning text-dark';
|
||||
} else if (publicDoc) {
|
||||
statusLabel = 'Umum';
|
||||
statusClass = 'bg-success';
|
||||
} else {
|
||||
statusLabel = 'Internal Unit';
|
||||
statusClass = 'bg-secondary';
|
||||
}
|
||||
|
||||
return `
|
||||
<tr>
|
||||
<td class="text-nowrap">${item.no_dokumen || '-'}</td>
|
||||
<td>
|
||||
<td class="file-cell">
|
||||
<span class="me-1">📄</span>
|
||||
<a href="#" class="file-link"
|
||||
<a href="#" class="file-link ${statusLabel === "Pending" ? 'fst-italic' : ''}"
|
||||
data-file="${item.file}"
|
||||
data-fileName="${fileName}"
|
||||
data-id="${item.file_directory_id}"
|
||||
@ -113,10 +167,22 @@
|
||||
data-tanggal_terbit="${item.tanggal_terbit || '-'}"
|
||||
data-permission_file="${item.permission_file || '-'}">${fileName}</a>
|
||||
</td>
|
||||
<td class="text-break"><span class="badge bg-light text-dark fw-semibold">${folderPath}</span></td>
|
||||
<td class="folder-cell">
|
||||
<a href="#"
|
||||
class="text-dark fw-semibold folder-prefill folder-link-sm ${statusLabel === "Pending" ? 'fst-italic' : ''}"
|
||||
title="${folderPath}"
|
||||
data-unit_id="${item.id_unit_kerja || ''}"
|
||||
data-sub_id="${item.id_sub_unit_kerja || ''}"
|
||||
data-kategori_id="${item.master_kategori_directory_id || ''}"
|
||||
data-unit_name="${unitName}"
|
||||
data-sub_name="${subName}"
|
||||
data-kategori_name="${kategoriName}">
|
||||
${folderPath}
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
<span class="badge ${publicDoc ? 'bg-success' : 'bg-secondary'}">
|
||||
${publicDoc ? 'Umum' : 'Internal Unit'}
|
||||
<span class="badge ${statusClass}">
|
||||
${statusLabel}
|
||||
</span>
|
||||
</td>
|
||||
<td class="text-nowrap">${formatTanggal(item.entry_at)}</td>
|
||||
@ -234,6 +300,38 @@
|
||||
}
|
||||
fetchData()
|
||||
|
||||
document.addEventListener('click', function (e) {
|
||||
const btn = e.target.closest('.folder-prefill');
|
||||
if (!btn) return;
|
||||
e.preventDefault();
|
||||
|
||||
const payload = {
|
||||
unitId: btn.getAttribute('data-unit_id') || '',
|
||||
subId: btn.getAttribute('data-sub_id') || '',
|
||||
kategoriId: btn.getAttribute('data-kategori_id') || '',
|
||||
unitName: btn.getAttribute('data-unit_name') || '',
|
||||
subName: btn.getAttribute('data-sub_name') || '',
|
||||
kategoriName: btn.getAttribute('data-kategori_name') || '',
|
||||
};
|
||||
|
||||
fetch('/dashboard/prefill', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').content,
|
||||
'X-Requested-With': 'XMLHttpRequest'
|
||||
},
|
||||
body: JSON.stringify(payload)
|
||||
})
|
||||
.then(res => {
|
||||
if (!res.ok) throw new Error('Gagal set filter');
|
||||
window.location.href = '/';
|
||||
})
|
||||
.catch(() => {
|
||||
Swal.fire({ icon: 'error', title: 'Gagal', text: 'Tidak bisa buka folder' });
|
||||
});
|
||||
});
|
||||
|
||||
let colCount = 1;
|
||||
$(document).ready(function() {
|
||||
$('.unit_kerja').select2({
|
||||
|
||||
@ -1,147 +1,177 @@
|
||||
<aside class="left-sidebar">
|
||||
<!-- Sidebar scroll-->
|
||||
<div>
|
||||
<div class="brand-logo d-flex align-items-center justify-content-between">
|
||||
<a href="/" class="text-nowrap logo-img">
|
||||
<img src="logo/logo_rsabhk.png" alt="rsabhk" width="180" class="mt-2"/>
|
||||
</a>
|
||||
<div class="close-btn d-xl-none d-block sidebartoggler cursor-pointer" id="sidebarCollapse">
|
||||
<i class="ti ti-x fs-6"></i>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Sidebar navigation-->
|
||||
<nav class="sidebar-nav scroll-sidebar" data-simplebar="">
|
||||
<ul id="sidebarnav">
|
||||
<li class="nav-small-cap">
|
||||
<iconify-icon icon="solar:menu-dots-linear" class="nav-small-cap-icon fs-4"></iconify-icon>
|
||||
<span class="hide-menu">Home</span>
|
||||
</li>
|
||||
<li class="sidebar-item">
|
||||
<a class="sidebar-link" href="/" aria-expanded="false">
|
||||
<i class="ti ti-dashboard"></i>
|
||||
<span class="hide-menu">Dashboard</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="sidebar-item">
|
||||
<a class="sidebar-link" href="/new" aria-expanded="false">
|
||||
<i class="ti ti-layout-dashboard"></i>
|
||||
<span class="hide-menu">Dashboard V2</span>
|
||||
</a>
|
||||
</li>
|
||||
<!-- ---------------------------------- -->
|
||||
<!-- Dashboard -->
|
||||
<!-- ---------------------------------- -->
|
||||
<li class="sidebar-item">
|
||||
<a class="sidebar-link justify-content-between"
|
||||
href="/master-kategori" aria-expanded="false">
|
||||
<div class="d-flex align-items-center gap-3">
|
||||
<span class="d-flex">
|
||||
<i class="ti ti-file"></i>
|
||||
</span>
|
||||
<span class="hide-menu">Master Kategori</span>
|
||||
</div>
|
||||
<div>
|
||||
{{-- Logo --}}
|
||||
<div class="brand-logo d-flex align-items-center justify-content-between">
|
||||
<a href="{{ url('/') }}" class="text-nowrap logo-img">
|
||||
<img src="{{ asset('logo/logo_rsabhk.png') }}" alt="rsabhk" width="180" class="mt-2" />
|
||||
</a>
|
||||
|
||||
</a>
|
||||
</li>
|
||||
{{-- <li class="sidebar-item">
|
||||
<a class="sidebar-link justify-content-between"
|
||||
href="/master-klasifikasi" aria-expanded="false">
|
||||
<div class="d-flex align-items-center gap-3">
|
||||
<span class="d-flex">
|
||||
<i class="ti ti-file"></i>
|
||||
</span>
|
||||
<span class="hide-menu">Master Klasifikasi</span>
|
||||
</div>
|
||||
</a>
|
||||
</li> --}}
|
||||
<li class="sidebar-item">
|
||||
<a class="sidebar-link justify-content-between"
|
||||
href="/akses" aria-expanded="false">
|
||||
<div class="d-flex align-items-center gap-3">
|
||||
<span class="d-flex">
|
||||
<i class="ti ti-lock-access"></i>
|
||||
</span>
|
||||
<span class="hide-menu">Akses</span>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li class="sidebar-item">
|
||||
<a class="sidebar-link justify-content-between"
|
||||
href="/log-activity" aria-expanded="false">
|
||||
<div class="d-flex align-items-center gap-3">
|
||||
<span class="d-flex">
|
||||
<i class="ti ti-activity"></i>
|
||||
</span>
|
||||
<span class="hide-menu">Log Aktivitas</span>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li class="sidebar-item">
|
||||
<a class="sidebar-link justify-content-between"
|
||||
href="/recap" aria-expanded="false">
|
||||
<div class="d-flex align-items-center gap-3">
|
||||
<span class="d-flex">
|
||||
<i class="ti ti-report-analytics"></i>
|
||||
</span>
|
||||
<span class="hide-menu">Data Rekap</span>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="sidebar-item">
|
||||
<a class="sidebar-link d-flex align-items-center justify-content-between"
|
||||
href="/pending-file" aria-expanded="false">
|
||||
|
||||
<!-- Left -->
|
||||
<div class="d-flex align-items-center gap-3">
|
||||
<i class="ti ti-clock sidebar-icon"></i>
|
||||
<span class="hide-menu">Persetujuan</span>
|
||||
</div>
|
||||
<!-- Right Badge -->
|
||||
<span class="badge bg-danger rounded-pill sidebar-badge" id="pendingCountBadge">
|
||||
0
|
||||
</span>
|
||||
|
||||
</a>
|
||||
</li>
|
||||
<li class="sidebar-item">
|
||||
<a class="sidebar-link justify-content-between"
|
||||
href="/master-persetujuan" aria-expanded="false">
|
||||
<div class="d-flex align-items-center gap-3">
|
||||
<span class="d-flex">
|
||||
<i class="ti ti-report-analytics"></i>
|
||||
</span>
|
||||
<span class="hide-menu">Master Persetujuan</span>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
<!-- End Sidebar navigation -->
|
||||
<div class="close-btn d-xl-none d-block sidebartoggler cursor-pointer" id="sidebarCollapse">
|
||||
<i class="ti ti-x fs-6"></i>
|
||||
</div>
|
||||
<!-- End Sidebar scroll-->
|
||||
</aside>
|
||||
<script>
|
||||
function countData(){
|
||||
const badge = document.getElementById('pendingCountBadge');
|
||||
if (!badge) return;
|
||||
fetch('/data/count-pending')
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
const count = data?.count ?? 0;
|
||||
badge.textContent = count;
|
||||
if (count <= 0) {
|
||||
badge.classList.add('d-none');
|
||||
} else {
|
||||
badge.classList.remove('d-none');
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
badge.classList.add('d-none');
|
||||
});
|
||||
}
|
||||
countData();
|
||||
</script>
|
||||
</div>
|
||||
|
||||
{{-- Sidebar nav --}}
|
||||
@php
|
||||
$openMaster = request()->is('akses*') || request()->is('master-kategori*') || request()->is('master-persetujuan*');
|
||||
@endphp
|
||||
|
||||
<nav class="sidebar-nav scroll-sidebar" data-simplebar="">
|
||||
<ul id="sidebarnav">
|
||||
|
||||
{{-- HOME --}}
|
||||
<li class="nav-small-cap"><span class="hide-menu">Home</span></li>
|
||||
|
||||
<li class="sidebar-item">
|
||||
<a class="sidebar-link" href="{{ url('/') }}" aria-expanded="false">
|
||||
<i class="ti ti-dashboard"></i>
|
||||
<span class="hide-menu">Dashboard</span>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li class="sidebar-item">
|
||||
<a class="sidebar-link" href="{{ url('/new') }}" aria-expanded="false">
|
||||
<i class="ti ti-layout-dashboard"></i>
|
||||
<span class="hide-menu">Dashboard V2</span>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
{{-- AKTIVITAS --}}
|
||||
<li class="nav-small-cap"><span class="hide-menu">Aktivitas</span></li>
|
||||
|
||||
<li class="sidebar-item">
|
||||
<a class="sidebar-link d-flex align-items-center justify-content-between"
|
||||
href="{{ url('/log-activity') }}" aria-expanded="false">
|
||||
<div class="d-flex align-items-center gap-3">
|
||||
<i class="ti ti-activity"></i>
|
||||
<span class="hide-menu">Log Aktivitas</span>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
@if($authUnit = auth()->user()->masterPersetujuan)
|
||||
<li class="sidebar-item">
|
||||
<a class="sidebar-link d-flex align-items-center justify-content-between"
|
||||
href="{{ url('/pending-file') }}" aria-expanded="false">
|
||||
|
||||
<div class="d-flex align-items-center gap-3">
|
||||
<i class="ti ti-clock"></i>
|
||||
<span class="hide-menu">Persetujuan</span>
|
||||
</div>
|
||||
|
||||
<span class="badge bg-danger rounded-pill d-none" id="pendingCountBadge">0</span>
|
||||
</a>
|
||||
</li>
|
||||
@endif
|
||||
{{-- RECAP --}}
|
||||
<li class="nav-small-cap"><span class="hide-menu">Recap</span></li>
|
||||
|
||||
<li class="sidebar-item">
|
||||
<a class="sidebar-link d-flex align-items-center justify-content-between"
|
||||
href="{{ url('/recap') }}" aria-expanded="false">
|
||||
<div class="d-flex align-items-center gap-3">
|
||||
<i class="ti ti-report-analytics"></i>
|
||||
<span class="hide-menu">Data Rekap</span>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
{{-- MASTER --}}
|
||||
@if(auth()->user()->akses && auth()->user()->akses->master_akses)
|
||||
<li class="nav-small-cap"><span class="hide-menu">Master</span></li>
|
||||
|
||||
<li class="sidebar-item has-sub {{ $openMaster ? 'open' : '' }}">
|
||||
<a class="sidebar-link d-flex align-items-center justify-content-between"
|
||||
href="#menu-master"
|
||||
data-bs-toggle="collapse"
|
||||
role="button"
|
||||
aria-expanded="{{ $openMaster ? 'true' : 'false' }}"
|
||||
aria-controls="menu-master">
|
||||
|
||||
<div class="d-flex align-items-center gap-3">
|
||||
<i class="ti ti-report-analytics"></i>
|
||||
<span class="hide-menu">Master</span>
|
||||
</div>
|
||||
|
||||
<i class="ti ti-chevron-right fs-6 sidebar-arrow"></i>
|
||||
</a>
|
||||
|
||||
<ul class="collapse sidebar-submenu {{ $openMaster ? 'show' : '' }}" id="menu-master">
|
||||
<li class="sidebar-item">
|
||||
<a href="{{ url('/akses') }}" class="sidebar-link">
|
||||
<span class="hide-menu">Akses</span>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li class="sidebar-item">
|
||||
<a href="{{ url('/master-kategori') }}" class="sidebar-link">
|
||||
<span class="hide-menu">Kategori</span>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li class="sidebar-item">
|
||||
<a href="{{ url('/master-persetujuan') }}" class="sidebar-link">
|
||||
<span class="hide-menu">Persetujuan</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
@endif
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
{{-- Styling kecil biar submenu rapi + arrow muter --}}
|
||||
<style>
|
||||
.sidebar-submenu { padding-left: 2.7rem; }
|
||||
.sidebar-submenu .sidebar-link { padding: 6px 0; font-size: 13px; opacity: .9; }
|
||||
|
||||
.sidebar-item.has-sub .sidebar-arrow { transition: transform .2s ease; }
|
||||
.sidebar-item.has-sub.open .sidebar-arrow { transform: rotate(90deg); }
|
||||
</style>
|
||||
|
||||
<script>
|
||||
const badge = document.getElementById('pendingCountBadge');
|
||||
|
||||
async function countData() {
|
||||
if (!badge) return;
|
||||
|
||||
try {
|
||||
const res = await fetch('/data/count-pending', {
|
||||
headers: { 'Accept': 'application/json' }
|
||||
});
|
||||
|
||||
if (!res.ok) throw new Error('Request failed: ' + res.status);
|
||||
|
||||
const data = await res.json();
|
||||
const count = Number(data?.count ?? 0);
|
||||
|
||||
badge.textContent = count;
|
||||
badge.classList.toggle('d-none', count <= 0);
|
||||
|
||||
} catch (e) {
|
||||
badge.classList.add('d-none');
|
||||
}
|
||||
}
|
||||
|
||||
countData();
|
||||
|
||||
setInterval(countData, 60000);
|
||||
|
||||
const masterCollapse = document.getElementById('menu-master');
|
||||
const masterItem = masterCollapse
|
||||
? masterCollapse.closest('.sidebar-item.has-sub')
|
||||
: null;
|
||||
|
||||
if (masterItem && masterCollapse) {
|
||||
masterCollapse.addEventListener('shown.bs.collapse', function () {
|
||||
masterItem.classList.add('open');
|
||||
});
|
||||
|
||||
masterCollapse.addEventListener('hidden.bs.collapse', function () {
|
||||
masterItem.classList.remove('open');
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@ -44,8 +44,11 @@
|
||||
<table class="table table-sm table-hover align-middle mb-0" id="lastUpdatedTable">
|
||||
<thead>
|
||||
<tr>
|
||||
@if(auth()->user()->masterPersetujuan)
|
||||
<th>Aksi</th>
|
||||
@endif
|
||||
<th>No Dokumen</th>
|
||||
<th>Status</th>
|
||||
<th>File</th>
|
||||
<th>Folder</th>
|
||||
<th>Unit/Sub Unit</th>
|
||||
|
||||
@ -18,15 +18,20 @@ Route::middleware(['auth'])->group(function(){
|
||||
Route::get('/file-preview/{id}', [DashboardController::class, 'dataPdf']);
|
||||
Route::post('/upload', [DashboardController::class, 'store']);
|
||||
Route::get('/data-unit-kerja', [DashboardController::class, 'dataUnitKerja']);
|
||||
Route::post('/dashboard/prefill', [DashboardController::class, 'setDashboardPrefill']);
|
||||
|
||||
Route::resource('/master-kategori', MasterKategoriController::class);
|
||||
Route::get('datatable/master-kategori', [MasterKategoriController::class, 'datatable']);
|
||||
Route::resource('/master-klasifikasi', MasterKlasifikasiController::class);
|
||||
Route::get('datatable/master-klasifikasi', [MasterKlasifikasiController::class, 'datatable']);
|
||||
Route::resource('/akses', AksesFileController::class);
|
||||
Route::get('datatable/akses', [AksesFileController::class, 'datatable']);
|
||||
Route::get('/select-pegawai', [AksesFileController::class, 'optionPegawai']);
|
||||
Route::get('/select-unit-kerja-option', [AksesFileController::class, 'optionUnitKerja']);
|
||||
Route::middleware(['akses.master'])->group(function () {
|
||||
Route::resource('/akses', AksesFileController::class);
|
||||
Route::get('datatable/akses', [AksesFileController::class, 'datatable']);
|
||||
Route::resource('/master-persetujuan', masterPersetujuanController::class)->only(['index','store','show','update','destroy']);
|
||||
Route::get('datatable/master-persetujuan', [masterPersetujuanController::class, 'datatable']);
|
||||
Route::resource('/master-kategori', MasterKategoriController::class);
|
||||
Route::get('datatable/master-kategori', [MasterKategoriController::class, 'datatable']);
|
||||
Route::resource('/master-klasifikasi', MasterKlasifikasiController::class);
|
||||
Route::get('datatable/master-klasifikasi', [MasterKlasifikasiController::class, 'datatable']);
|
||||
});
|
||||
|
||||
Route::get('/select-unit-kerja', [DashboardController::class, 'OptionUnitKerja']);
|
||||
Route::get('/select-sub-unit-kerja/{id}', [DashboardController::class, 'optionSubUnitKerja']);
|
||||
@ -42,14 +47,15 @@ Route::middleware(['auth'])->group(function(){
|
||||
Route::get('/recap', [DashboardController::class, 'recapView']);
|
||||
Route::get('/data/recap', [DashboardController::class, 'recapData']);
|
||||
|
||||
Route::get('/pending-file', [DashboardController::class, 'pendingFile']);
|
||||
Route::get('/datatable/pending-file', [DashboardController::class, 'dataPendingFile']);
|
||||
Route::post('/pending-file/{id}/approve', [DashboardController::class, 'approvePendingFile']);
|
||||
Route::post('/pending-file/{id}/reject', [DashboardController::class, 'rejectPendingFile']);
|
||||
Route::get('/data/count-pending', [DashboardController::class, 'countDataPending']);
|
||||
|
||||
Route::resource('/master-persetujuan', masterPersetujuanController::class)->only(['index','store','show','update','destroy']);
|
||||
Route::get('datatable/master-persetujuan', [masterPersetujuanController::class, 'datatable']);
|
||||
|
||||
Route::middleware(['master.persetujuan'])->group(function () {
|
||||
Route::get('/pending-file', [DashboardController::class, 'pendingFile']);
|
||||
Route::get('/datatable/pending-file', [DashboardController::class, 'dataPendingFile']);
|
||||
Route::post('/pending-file/{id}/approve', [DashboardController::class, 'approvePendingFile']);
|
||||
Route::post('/pending-file/{id}/reject', [DashboardController::class, 'rejectPendingFile']);
|
||||
Route::get('/data/count-pending', [DashboardController::class, 'countDataPending']);
|
||||
});
|
||||
});
|
||||
|
||||
Route::get('/login', [AuthController::class, 'index'])->name('login');
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user