2026-03-25 12:05:33 +09:00
< ? php
2026-06-08 09:47:36 +09:00
declare ( strict_types = 1 );
/**
* 관리자 공통 레이아웃 — gov - portal 디자인 적용판 .
* 헤더 + 관리자 대메뉴 ( 클릭 ) + 좌측 사이드바 ( 소메뉴 ) + 본문 ( $content ) .
*
* @ var string $title
* @ var string $content
*/
2026-03-25 12:05:33 +09:00
helper ( 'admin' );
2026-06-08 09:47:36 +09:00
$mbLevel = ( int ) session () -> get ( 'mb_level' );
2026-03-26 15:29:55 +09:00
$isSuperAdmin = \Config\Roles :: isSuperAdminEquivalent ( $mbLevel );
2026-06-08 09:47:36 +09:00
$mbName = ( string ) ( session () -> get ( 'mb_name' ) ? ? '담당자' );
$levelName = config ( \Config\Roles :: class ) -> getLevelName ( $mbLevel );
$effectiveLgIdx = admin_effective_lg_idx ();
$effectiveLgName = '' ;
2026-03-25 12:05:33 +09:00
if ( $effectiveLgIdx ) {
$lgRow = model ( \App\Models\LocalGovernmentModel :: class ) -> find ( $effectiveLgIdx );
2026-06-08 09:47:36 +09:00
$effectiveLgName = $lgRow ? ( string ) $lgRow -> lg_name : '' ;
2026-03-25 12:05:33 +09:00
}
2026-04-08 00:18:01 +09:00
2026-06-08 09:47:36 +09:00
$adminTree = function_exists ( 'get_admin_nav_tree' ) ? get_admin_nav_tree () : [];
$gov = gov_portal_nav_context ( false , $adminTree );
2026-04-14 00:41:14 +09:00
2026-06-08 09:47:36 +09:00
// 관리자 메뉴가 비어 있으면(지자체 미선택 등) 핵심 항목 폴백 노출
$navItems = $gov [ 'navItems' ];
if ( $navItems === []) {
$mk = static fn ( string $name , string $path ) : array => [
'idx' => 0 , 'name' => $name , 'href' => $path , 'url' => base_url ( $path ),
];
$navItems = [
[ 'idx' => 0 , 'name' => '대시보드' , 'href' => 'admin' , 'url' => base_url ( 'admin' ), 'children' => [], 'hasChildren' => false ],
[ 'idx' => 0 , 'name' => '회원·접근' , 'href' => '' , 'url' => '' , 'hasChildren' => true , 'children' => [
$mk ( '회원 관리' , 'admin/users' ), $mk ( '로그인 이력' , 'admin/access/login-history' ), $mk ( '승인 대기' , 'admin/access/approvals' ),
]],
[ 'idx' => 0 , 'name' => '시스템' , 'href' => '' , 'url' => '' , 'hasChildren' => true , 'children' => [
$mk ( '역할' , 'admin/roles' ), $mk ( '메뉴' , 'admin/menus' ),
]],
];
if ( $isSuperAdmin ) {
$navItems [] = [ 'idx' => 0 , 'name' => '지자체' , 'href' => '' , 'url' => '' , 'hasChildren' => true , 'children' => [
$mk ( '지자체 전환' , 'admin/select-local-government' ), $mk ( '지자체 관리' , 'admin/local-governments' ),
]];
}
}
$navJson = json_encode ( $navItems , JSON_UNESCAPED_UNICODE | JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS );
$navPartial = [
'govNavItems' => $navItems ,
'govNavJson' => $navJson ,
'govActiveParentIdx' => $gov [ 'activeParentIdx' ],
'govCurrentPath' => $gov [ 'currentPath' ],
'govDashboardAliases' => $gov [ 'dashboardAliases' ],
'govActiveChildHref' => $gov [ 'currentPath' ],
];
2026-03-25 12:05:33 +09:00
?>
<! DOCTYPE html >
2026-06-08 09:47:36 +09:00
< html lang = " ko " class = " gov-portal-html " >
2026-03-25 12:05:33 +09:00
< head >
< meta charset = " utf-8 " />
< meta content = " width=device-width, initial-scale=1.0 " name = " viewport " />
2026-06-09 14:43:24 +09:00
< title >< ? = esc ( $title ? ? '관리자' ) ?> - GBLS</title>
2026-06-08 09:47:36 +09:00
< link href = " https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css " rel = " stylesheet " />
< link rel = " stylesheet " href = " https://cdn.jsdelivr.net/gh/orioncactus/pretendard@v1.3.9/dist/web/static/pretendard.min.css " />
2026-03-25 12:05:33 +09:00
< script src = " https://cdn.tailwindcss.com?plugins=forms,container-queries " ></ script >
< script >
tailwind . config = {
theme : {
extend : {
2026-06-08 09:47:36 +09:00
fontFamily : { sans : [ 'Pretendard' , '"Malgun Gothic"' , '"Noto Sans KR"' , 'sans-serif' ] },
colors : {
'system-header' : '#ffffff' , 'title-bar' : '#1a2b4b' , 'control-panel' : '#f8f9fa' ,
'btn-search' : '#243a5e' , 'btn-excel-border' : '#28a745' , 'btn-excel-text' : '#28a745' ,
'btn-print-border' : '#ced4da' , 'btn-exit' : '#d9534f' ,
2026-03-25 12:05:33 +09:00
},
fontSize : { 'xxs' : '0.65rem' }
}
}
}
</ script >
2026-06-08 09:47:36 +09:00
< style >
< ? php include __DIR__ . '/../home/_dashboard_gov_portal_brand_css.php' ; ?>
< ? php include __DIR__ . '/../home/_dashboard_gov_portal_topnav_css.php' ; ?>
< ? php include __DIR__ . '/../home/_dashboard_gov_portal_chrome_css.php' ; ?>
. data - table { width : 100 % ; border - collapse : collapse ; font - family : 'Pretendard' , 'Malgun Gothic' , 'Noto Sans KR' , sans - serif ; }
2026-06-11 17:26:36 +09:00
. data - table { font - size : 13 px ; }
. data - table th , . data - table td { text - align : left ; padding : 0.55 rem 0.5 rem ; white - space : nowrap ; border : 0 ; border - bottom : 1 px solid #e5e7eb; }
. data - table thead th { font - size : 0.6875 rem ; font - weight : 600 ; color : #6b7280; background: transparent; vertical-align: middle; }
. data - table tbody td { color : #374151; }
. data - table tbody tr : last - child td { border - bottom : 0 ; }
. data - table tbody tr : hover td { background - color : #f9fafb; }
2026-03-26 16:40:49 +09:00
@ media print {
2026-06-08 09:47:36 +09:00
. portal - header , . sidebar , . portal - footer , . no - print , nav . portal - top - nav { display : none ! important ; }
body . gov - portal - shell { background : #fff; display: block; }
. gov - portal - shell . main . work - main { overflow : visible ! important ; padding : 0 ! important ; }
2026-03-26 16:40:49 +09:00
. print - header { display : block ! important ; }
}
2026-03-25 12:05:33 +09:00
</ style >
</ head >
2026-06-08 09:47:36 +09:00
< body class = " gov-portal-shell select-none " >
< header class = " portal-header " >
< div class = " portal-header-inner " >
2026-06-13 22:56:29 +09:00
< ? = view ( 'home/_dashboard_gov_portal_brand' , [ 'brandHref' => base_url ( '/' )]) ?>
2026-06-08 09:47:36 +09:00
< ? = view ( 'home/_dashboard_gov_portal_topnav_click' , $navPartial ) ?>
< div class = " portal-header-utils " style = " display:flex;align-items:center;gap:.5rem; " >
2026-06-15 13:31:31 +09:00
< div class = " ws-fontctl " title = " 글씨 크기 조절 " style = " display:inline-flex;align-items:center;gap:2px;background:rgba(255,255,255,.1);border:1px solid rgba(255,255,255,.25);border-radius:6px;padding:1px; " >
< button type = " button " id = " wsFontMinus " title = " 글씨 작게 " style = " width:24px;height:22px;border:0;background:transparent;color:#fff;cursor:pointer;font-size:11px;line-height:1;border-radius:5px; " > A− </ button >
< span id = " wsFontPct " style = " min-width:34px;text-align:center;color:#fff;font-size:.68rem;font-weight:600; " > 100 %</ span >
< button type = " button " id = " wsFontPlus " title = " 글씨 크게 " style = " width:24px;height:22px;border:0;background:transparent;color:#fff;cursor:pointer;font-size:14px;line-height:1;border-radius:5px; " > A +</ button >
</ div >
2026-06-08 09:47:36 +09:00
< span class = " user-line " >
< ? php if ( $effectiveLgName !== '' ) : ?> <strong><?= esc($effectiveLgName) ?></strong> · <?php endif; ?>
< ? = esc ( $levelName ) ?> · <?= esc($mbName) ?>님
</ span >
< a href = " <?= base_url('/') ?> " title = " 사이트로 "
style = " display:inline-flex;align-items:center;gap:.3rem;padding:.25rem .6rem;border-radius:6px;background:rgba(255,255,255,.14);border:1px solid rgba(255,255,255,.3);color:#fff;text-decoration:none;font-size:.75rem;font-weight:600;white-space:nowrap; " >
< i class = " fa-solid fa-house " ></ i > 사이트
2026-04-08 00:18:01 +09:00
</ a >
2026-06-08 09:47:36 +09:00
< a href = " <?= base_url('logout') ?> " title = " 로그아웃 "
style = " display:inline-flex;align-items:center;gap:.3rem;padding:.25rem .6rem;border-radius:6px;background:rgba(255,255,255,.08);border:1px solid rgba(255,255,255,.22);color:#fff;text-decoration:none;font-size:.75rem;font-weight:600;white-space:nowrap; " >
< i class = " fa-solid fa-right-from-bracket " ></ i > 로그아웃
</ a >
</ div >
</ div >
</ header >
< div class = " layout " >
< ? = view ( 'home/_dashboard_gov_portal_sidebar' , $navPartial ) ?>
< main class = " main work-main main-content-area " >
< ? php if ( ! empty ( $title )) : ?>
< h1 class = " work-titlebar " >< i class = " fa-solid fa-gear tb-ico " ></ i >< ? = esc ( $title ) ?> </h1>
< ? php endif ; ?>
< ? php if ( session () -> getFlashdata ( 'success' )) : ?>
< div class = " work-flash ok " >< ? = esc ( session () -> getFlashdata ( 'success' )) ?> </div>
< ? php endif ; ?>
< ? php if ( session () -> getFlashdata ( 'error' )) : ?>
< div class = " work-flash err " >< ? = esc ( session () -> getFlashdata ( 'error' )) ?> </div>
< ? php endif ; ?>
< ? php if ( session () -> getFlashdata ( 'errors' )) : ?>
< div class = " work-flash err " >< ? php foreach ( session () -> getFlashdata ( 'errors' ) as $err ) : ?> <div><?= esc($err) ?></div><?php endforeach; ?></div>
< ? php endif ; ?>
< div class = " work-surface " >
< ? = $content ?>
2026-04-08 00:18:01 +09:00
</ div >
2026-06-08 09:47:36 +09:00
</ main >
</ div >
< footer class = " portal-footer " >
2026-06-09 14:43:24 +09:00
< span > GBLS 관리자 </ span >
2026-06-08 09:47:36 +09:00
< span >< ? = date ( 'Y.m.d (D) H:i' ) ?> </span>
</ footer >
< ? = view ( 'home/_dashboard_gov_portal_nav_script_base' , $navPartial ) ?>
2026-06-08 12:26:19 +09:00
< script >
( function () {
// bfcache 복원 시 열린 채 남은 모달/팝업으로 회색 레이어가 클릭을 막는 문제 방지
function closeStuckOverlays () {
document . querySelectorAll ( '.fixed.inset-0[id$="-modal"], .fixed.inset-0[id$="-popup"]' ) . forEach ( function ( el ) {
el . classList . add ( 'hidden' ); el . setAttribute ( 'aria-hidden' , 'true' );
});
document . body . style . overflow = '' ;
}
window . addEventListener ( 'pageshow' , function ( e ) { if ( e . persisted ) closeStuckOverlays (); });
window . addEventListener ( 'pagehide' , closeStuckOverlays );
})();
2026-06-15 13:31:31 +09:00
// 글씨 크기 조절(A− /A+) — 본문 + 상단 대메뉴 + 좌측 사이드바에 zoom 적용. 사이트/워크스페이스와 배율 공유.
( function () {
var FONT_KEY = 'jrj_font_scale' ;
var scaleSelectors = [ '.portal-header' , '.sidebar' , '.work-main' ];
function curScale () { var s = parseInt ( localStorage . getItem ( FONT_KEY ) || '100' , 10 ); return ( s >= 70 && s <= 150 ) ? s : 100 ; }
function applyScale ( s ) {
s = Math . min ( 150 , Math . max ( 70 , s ));
try { localStorage . setItem ( FONT_KEY , String ( s )); } catch ( e ) {}
var z = s / 100 ;
scaleSelectors . forEach ( function ( sel ) { var el = document . querySelector ( sel ); if ( el ) el . style . zoom = z ; });
var pct = document . getElementById ( 'wsFontPct' ); if ( pct ) pct . textContent = s + '%' ;
}
applyScale ( curScale ());
var plus = document . getElementById ( 'wsFontPlus' ), minus = document . getElementById ( 'wsFontMinus' );
if ( plus ) plus . addEventListener ( 'click' , function () { applyScale ( curScale () + 10 ); });
if ( minus ) minus . addEventListener ( 'click' , function () { applyScale ( curScale () - 10 ); });
window . addEventListener ( 'storage' , function ( e ) { if ( e . key === FONT_KEY ) applyScale ( curScale ()); });
})();
2026-06-08 12:26:19 +09:00
</ script >
2026-03-25 12:05:33 +09:00
</ body >
</ html >