diff --git a/app/Controllers/Admin/Menu.php b/app/Controllers/Admin/Menu.php index f657a39..0307f64 100644 --- a/app/Controllers/Admin/Menu.php +++ b/app/Controllers/Admin/Menu.php @@ -345,7 +345,7 @@ class Menu extends BaseController ]); } - return redirect()->to(base_url('admin/dashboard')) + return redirect()->to(base_url('admin')) ->with('error', '메뉴 관리는 레벨4 이상만 접근할 수 있습니다.'); } } diff --git a/app/Controllers/Auth.php b/app/Controllers/Auth.php index 554989a..78bb43b 100644 --- a/app/Controllers/Auth.php +++ b/app/Controllers/Auth.php @@ -22,7 +22,10 @@ class Auth extends BaseController return redirect()->to('/'); } - return view('auth/login'); + return view('auth/login', [ + 'pageTitle' => '로그인 - 종량제 시스템', + 'cardMax' => 'max-w-md', + ]); } public function login() @@ -156,7 +159,9 @@ class Auth extends BaseController } return view('auth/login_two_factor', [ - 'memberId' => $member->mb_id, + 'memberId' => $member->mb_id, + 'pageTitle' => '2차 인증 - 종량제 시스템', + 'cardMax' => 'max-w-md', ]); } @@ -239,6 +244,8 @@ class Auth extends BaseController 'memberId' => $member->mb_id, 'qrDataUri' => $qrDataUri, 'secret' => $secret, + 'pageTitle' => '2차 인증 등록 - 종량제 시스템', + 'cardMax' => 'max-w-lg', ]); } @@ -341,6 +348,8 @@ class Auth extends BaseController return view('auth/register', [ 'localGovernments' => $localGovernments, + 'pageTitle' => '회원가입 - 종량제 시스템', + 'cardMax' => 'max-w-md', ]); } diff --git a/app/Controllers/Bag.php b/app/Controllers/Bag.php index 8a9babe..8786818 100644 --- a/app/Controllers/Bag.php +++ b/app/Controllers/Bag.php @@ -214,7 +214,8 @@ class Bag extends BaseController private function render(string $title, string $viewFile, array $data = []): string { - return view('bag/layout/main', [ + // 사이트 업무 페이지 공통 셸: gov-portal 디자인(헤더+대메뉴+클릭형 좌측 사이드바). + return view('bag/layout/portal', [ 'title' => $title, 'content' => view($viewFile, $data), ]); diff --git a/app/Controllers/BaseController.php b/app/Controllers/BaseController.php index 07c6ae9..3845550 100644 --- a/app/Controllers/BaseController.php +++ b/app/Controllers/BaseController.php @@ -61,7 +61,8 @@ abstract class BaseController extends Controller $path = substr($path, strlen('index.php/')); } if ($path === 'bag' || str_starts_with($path, 'bag/')) { - return view('bag/layout/main', [ + // 사이트 업무 페이지: gov-portal 디자인 셸 적용 + return view('bag/layout/portal', [ 'title' => $title, 'content' => $content, ]); diff --git a/app/Controllers/Home.php b/app/Controllers/Home.php index 7713cf8..a2fc687 100644 --- a/app/Controllers/Home.php +++ b/app/Controllers/Home.php @@ -10,14 +10,141 @@ class Home extends BaseController public function index() { if (session()->get('logged_in')) { - // 메인(/) 본문은 「요약(simple)」 대시보드로 노출한다. - // 종래의 「종합·그래프(blend)」 본문은 /dashboard (또는 /dashboard/blend)로 이동. - return $this->dashboardSimple(); + // 메인(/) — gov-portal 디자인 셸 + 종량제 실데이터 대시보드. + helper('admin'); + + return view('bag/layout/portal', [ + 'title' => '업무 현황', + 'bare' => true, + 'content' => view('bag/dashboard_portal', $this->portalDashboardData()), + ]); } return view('welcome_message'); } + /** + * 메인 대시보드용 — 종량제 시스템에 실제 존재하는 데이터만 집계. + * + * @return array + */ + private function portalDashboardData(): array + { + helper('admin'); + $db = \Config\Database::connect(); + $lgIdx = function_exists('admin_effective_lg_idx') ? admin_effective_lg_idx() : null; + if ($lgIdx === null) { + $raw = session()->get('mb_lg_idx'); + $lgIdx = ($raw !== null && $raw !== '') ? (int) $raw : null; + } + + $inventory = []; + $totalQty = 0; + $orderCount = 0; + $palette = ['#3b82f6', '#10b981', '#f59e0b', '#6366f1', '#ef4444', '#0ea5e9', '#14b8a6', '#a855f7', '#f97316']; + + try { + if ($lgIdx !== null && $db->tableExists('bag_inventory')) { + $rows = $db->table('bag_inventory') + ->select('bi_bag_name, bi_bag_code, bi_qty') + ->where('bi_lg_idx', $lgIdx) + ->orderBy('bi_qty', 'DESC') + ->get()->getResultArray(); + foreach ($rows as $r) { + $inventory[] = [ + 'name' => (string) ($r['bi_bag_name'] ?? $r['bi_bag_code'] ?? ''), + 'qty' => (int) ($r['bi_qty'] ?? 0), + ]; + $totalQty += (int) ($r['bi_qty'] ?? 0); + } + } + } catch (\Throwable $e) { + $inventory = []; + } + + // 재고 구성(상위 품목 비율) + $stockMix = []; + foreach (array_slice($inventory, 0, 6) as $i => $item) { + $stockMix[] = [ + 'name' => $item['name'], + 'value' => $totalQty > 0 ? (int) round($item['qty'] / $totalQty * 100) : 0, + 'color' => $palette[$i % count($palette)], + ]; + } + // 부족 재고(수량 적은 하위 품목) — 최대 재고 대비 비율 + $maxQty = $inventory !== [] ? max(array_column($inventory, 'qty')) : 0; + $lowStock = []; + foreach (array_slice(array_reverse($inventory), 0, 5) as $item) { + $lowStock[] = [ + 'name' => $item['name'], + 'qty' => $item['qty'], + 'percent' => $maxQty > 0 ? (int) round($item['qty'] / $maxQty * 100) : 0, + ]; + } + + try { + if ($lgIdx !== null && $db->tableExists('shop_order')) { + $orderCount = (int) $db->table('shop_order') + ->where('so_lg_idx', $lgIdx) + ->where('so_status', 'normal') + ->countAllResults(); + } + } catch (\Throwable $e) { + $orderCount = 0; + } + + $pendingApprovals = 0; + try { + if ($db->tableExists('member_approval_request')) { + $pendingApprovals = (int) $db->table('member_approval_request') + ->where('mar_status', 'pending') + ->countAllResults(); + } + } catch (\Throwable $e) { + $pendingApprovals = 0; + } + + // 최근 활동(activity_log) — 실제 변경 이력 + $actionLabel = ['create' => '등록', 'update' => '수정', 'delete' => '삭제', 'cancel' => '취소']; + $tableLabel = [ + 'bag_order' => '발주', 'bag_receiving' => '입고', 'bag_sale' => '판매', + 'bag_issue' => '불출', 'bag_inventory' => '재고', 'shop_order' => '주문접수', + 'designated_shop' => '지정판매소', 'bag_price' => '단가', 'member' => '회원', + ]; + $recent = []; + try { + if ($db->tableExists('activity_log')) { + $logs = $db->table('activity_log') + ->select('al_action, al_table, al_regdate') + ->orderBy('al_idx', 'DESC')->limit(6)->get()->getResultArray(); + foreach ($logs as $l) { + $t = (string) ($l['al_regdate'] ?? ''); + $recent[] = [ + 'time' => $t !== '' ? date('m.d H:i', strtotime($t)) : '', + 'text' => ($tableLabel[$l['al_table']] ?? (string) $l['al_table']) + . ' ' . ($actionLabel[$l['al_action']] ?? (string) $l['al_action']), + ]; + } + } + } catch (\Throwable $e) { + $recent = []; + } + + return [ + 'lgLabel' => $this->resolveLgLabel(), + 'mbName' => (string) (session()->get('mb_name') ?? '담당자'), + 'mbId' => (string) (session()->get('mb_id') ?? ''), + 'levelName' => config(\Config\Roles::class)->getLevelName((int) session()->get('mb_level')), + 'totalQty' => $totalQty, + 'itemCount' => count($inventory), + 'orderCount' => $orderCount, + 'pendingApprovals' => $pendingApprovals, + 'stockMix' => $stockMix, + 'lowStock' => $lowStock, + 'recentActivity' => $recent, + ]; + } + /** * 로그인 후 메인 — site 메뉴 레이아웃 + 종합·그래프(blend) 본문 */ diff --git a/app/Helpers/admin_helper.php b/app/Helpers/admin_helper.php index e638db4..853ab8b 100644 --- a/app/Helpers/admin_helper.php +++ b/app/Helpers/admin_helper.php @@ -687,11 +687,11 @@ if (! function_exists('gov_portal_nav_context')) { * dashboardAliases: list * } */ - function gov_portal_nav_context(): array + function gov_portal_nav_context(bool $remapLinks = true, ?array $tree = null): array { helper('url'); - $tree = get_site_nav_tree(); + $tree = $tree ?? get_site_nav_tree(); $rawPath = current_nav_request_path(); $variant = gov_portal_active_variant($rawPath); $currentPath = gov_portal_nav_match_path($rawPath); @@ -702,10 +702,10 @@ if (! function_exists('gov_portal_nav_context')) { foreach ($tree as $pIdx => $parent) { $children = []; foreach ($parent->children ?? [] as $child) { - $href = gov_portal_menu_href_remap( - menu_link_preferred_href_path($child->mm_link ?? null, $currentPath), - $variant - ); + $href = menu_link_preferred_href_path($child->mm_link ?? null, $currentPath); + if ($remapLinks) { + $href = gov_portal_menu_href_remap($href, $variant); + } $children[] = [ 'idx' => (int) ($child->mm_idx ?? 0), 'name' => (string) ($child->mm_name ?? ''), diff --git a/app/Views/admin/layout.php b/app/Views/admin/layout.php index 8a0996a..71ccae7 100644 --- a/app/Views/admin/layout.php +++ b/app/Views/admin/layout.php @@ -1,181 +1,151 @@ getUri(); -$n = $uriObj->getTotalSegments(); -$uri = $n >= 2 ? $uriObj->getSegment(2) : ''; -$seg3 = $n >= 3 ? $uriObj->getSegment(3) : ''; -$mbLevel = (int) session()->get('mb_level'); + +$mbLevel = (int) session()->get('mb_level'); $isSuperAdmin = \Config\Roles::isSuperAdminEquivalent($mbLevel); -$effectiveLgIdx = admin_effective_lg_idx(); -$effectiveLgName = null; +$mbName = (string) (session()->get('mb_name') ?? '담당자'); +$levelName = config(\Config\Roles::class)->getLevelName($mbLevel); + +$effectiveLgIdx = admin_effective_lg_idx(); +$effectiveLgName = ''; if ($effectiveLgIdx) { $lgRow = model(\App\Models\LocalGovernmentModel::class)->find($effectiveLgIdx); - $effectiveLgName = $lgRow ? $lgRow->lg_name : null; + $effectiveLgName = $lgRow ? (string) $lgRow->lg_name : ''; } -$userNav = session_user_nav_display(); -$currentPath = current_nav_request_path(); -$adminNavTree = get_admin_nav_tree(); -/** DB 링크(mm_link)만 사용. 짧게 적은 항목(menus 등)은 실제 URI(admin/menus)와 맞춰 후보 비교 */ -$adminNavItemIsCurrent = static function (?string $mmLink) use ($currentPath): bool { - return menu_link_matches_request($mmLink, $currentPath, []); -}; +$adminTree = function_exists('get_admin_nav_tree') ? get_admin_nav_tree() : []; +$gov = gov_portal_nav_context(false, $adminTree); -/** 메뉴가 DB에서 안 쓰일 때만(폴백 상단바) 세그먼트 기반 활성 */ -$isActive = static function (string $path) use ($uri, $seg3) { - if ($path === 'admin' || $path === '') return $uri === ''; - if ($path === 'users') return $uri === 'users'; - if ($path === 'login-history') return $uri === 'access' && $seg3 === 'login-history'; - if ($path === 'approvals') return $uri === 'access' && $seg3 === 'approvals'; - if ($path === 'roles') return $uri === 'roles'; - if ($path === 'menus') return $uri === 'menus'; - if ($path === 'local-governments') return $uri === 'local-governments'; - if ($path === 'select-local-government') return $uri === 'select-local-government'; - if ($path === 'designated-shops') return $uri === 'designated-shops'; - return false; -}; +// 관리자 메뉴가 비어 있으면(지자체 미선택 등) 핵심 항목 폴백 노출 +$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'], +]; ?> - + <?= esc($title ?? '관리자') ?> - 종량제 시스템 + + - - - - -
-
- base_url('admin')]) ?> -
- - $userNav, - 'effectiveLgName' => $effectiveLgName, - 'showSiteLink' => true, - 'showAdminLink' => false, - ]) ?> -
-
- -
-getFlashdata('success')): ?> - - -getFlashdata('error')): ?> - - -getFlashdata('errors')): ?> - - -
- -
-
- 종량제 시스템 관리자 - -
+ + + +
+ + +
+ +

+ + getFlashdata('success')): ?> +
getFlashdata('success')) ?>
+ + getFlashdata('error')): ?> +
getFlashdata('error')) ?>
+ + getFlashdata('errors')): ?> +
getFlashdata('errors') as $err): ?>
+ +
+ +
+
+
+ +
+ 종량제 시스템 관리자 + +
+ + diff --git a/app/Views/auth/_shell.php b/app/Views/auth/_shell.php new file mode 100644 index 0000000..325413b --- /dev/null +++ b/app/Views/auth/_shell.php @@ -0,0 +1,70 @@ +extend('auth/_shell'), + * 섹션 'heading'(카드 제목)·'content'(본문) 정의. + * 선택 변수: $subtitle(카드 헤더 소제목), $cardMax(예: 'max-w-lg', 기본 'max-w-md') + */ +$cardMax = $cardMax ?? 'max-w-md'; +$subtitle = $subtitle ?? '종량제 쓰레기봉투 물류시스템'; +?> + + + + + +<?= esc($pageTitle ?? '종량제 시스템') ?> + + + + + + + +
+ + + 종량제 시스템 + +
+ +
+
+
+

+

renderSection('heading') ?>

+
+
+ getFlashdata('error')): ?> + + + getFlashdata('errors')): ?> + + + getFlashdata('success')): ?> + + + renderSection('content') ?> +
+
+
+
종량제 물류시스템
+ + diff --git a/app/Views/auth/login.php b/app/Views/auth/login.php index 79456ce..cadf9df 100644 --- a/app/Views/auth/login.php +++ b/app/Views/auth/login.php @@ -1,72 +1,21 @@ - - - - - -로그인 - 종량제 시스템 - - - - - - - -
- - - 종량제 시스템 - -
-
- 로그인 -
-getFlashdata('success')): ?> - - -getFlashdata('error')): ?> - - -getFlashdata('errors')): ?> - - -
-
-
- -
- - -
-
- - -
-
- - 회원가입 -
-
-
-
-
종량제 시스템
- - +extend('auth/_shell') ?> + +section('heading') ?>로그인endSection() ?> + +section('content') ?> +
+ +
+ + +
+
+ + +
+
+ + 회원가입 +
+
+endSection() ?> diff --git a/app/Views/auth/login_two_factor.php b/app/Views/auth/login_two_factor.php index 67f13a3..bb4013b 100644 --- a/app/Views/auth/login_two_factor.php +++ b/app/Views/auth/login_two_factor.php @@ -1,60 +1,18 @@ - - - - - -2차 인증 - 종량제 시스템 - - - - - - - -
- -
-
- 2차 인증 (TOTP) -
-getFlashdata('error')): ?> - - -getFlashdata('errors')): ?> - - -
-
-

계정 에 대해 인증 앱의 6자리 코드를 입력해 주세요.

-
- -
- - -
-
- - 처음으로 -
-
-
-
-
종량제 시스템
- - +extend('auth/_shell') ?> + +section('heading') ?>2차 인증 (TOTP)endSection() ?> + +section('content') ?> +

계정 에 대해 인증 앱의 6자리 코드를 입력해 주세요.

+
+ +
+ + +
+
+ + 처음으로 +
+
+endSection() ?> diff --git a/app/Views/auth/register.php b/app/Views/auth/register.php index 60425c9..7c6ca94 100644 --- a/app/Views/auth/register.php +++ b/app/Views/auth/register.php @@ -1,101 +1,59 @@ - - - - - -회원가입 - 종량제 시스템 - - - - - - - -
- -
-
- 회원가입 -
-getFlashdata('error')): ?> - - -getFlashdata('errors')): ?> - - -
-
-
- -
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -

가입 후 관리자 승인 완료 시 로그인할 수 있습니다.

-
-
- - 로그인 -
-
-
-
-
종량제 시스템
- - +extend('auth/_shell') ?> + +section('heading') ?>회원가입endSection() ?> + +section('content') ?> + +
+ +
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +

가입 후 관리자 승인 완료 시 로그인할 수 있습니다.

+
+
+ + 로그인 +
+
+endSection() ?> diff --git a/app/Views/auth/totp_setup.php b/app/Views/auth/totp_setup.php index b7280bd..5eb14bd 100644 --- a/app/Views/auth/totp_setup.php +++ b/app/Views/auth/totp_setup.php @@ -1,70 +1,29 @@ - - - - - -2차 인증 등록 - 종량제 시스템 - - - - - - - -
- -
-
- 2차 인증 앱 등록 +extend('auth/_shell') ?> + +section('heading') ?>2차 인증 앱 등록endSection() ?> + +section('content') ?> +

관리자 계정 에 Google Authenticator, Microsoft Authenticator 등으로 아래 시크릿 또는 QR을 등록한 뒤, 표시되는 6자리 코드를 입력해 주세요.

+ +
+ TOTP QR 코드
-getFlashdata('error')): ?> - + +

QR 이미지를 불러올 수 없습니다. 아래 시크릿을 앱에 직접 입력해 주세요.

-getFlashdata('errors')): ?> - diff --git a/app/Views/bag/code_kinds.php b/app/Views/bag/code_kinds.php index 5e0e575..0d1cd4b 100644 --- a/app/Views/bag/code_kinds.php +++ b/app/Views/bag/code_kinds.php @@ -19,7 +19,7 @@ $detailColCount = 7 + ($canManageDetails ? 1 : 0);

기본코드 종류

- 기본코드 등록 + 기본코드 등록 코드 종류 등록·수정은 super admin·본부 관리자만 가능합니다. @@ -81,7 +81,7 @@ $detailColCount = 7 + ($canManageDetails ? 1 : 0); - 세부코드 등록 + 세부코드 등록
diff --git a/app/Views/bag/daily_inventory.php b/app/Views/bag/daily_inventory.php index bb9e4fe..09e5f0d 100644 --- a/app/Views/bag/daily_inventory.php +++ b/app/Views/bag/daily_inventory.php @@ -32,7 +32,7 @@ $userNav = session_user_nav_display(); 'system-header': '#ffffff', 'title-bar': '#2c3e50', 'control-panel': '#f8f9fa', - 'btn-search': '#1c4e80', + 'btn-search': '#243a5e', 'btn-excel-border': '#28a745', 'btn-excel-text': '#28a745', 'btn-print-border': '#ced4da', diff --git a/app/Views/bag/dashboard_blend_inner.php b/app/Views/bag/dashboard_blend_inner.php index c7cc3bc..80d3953 100644 --- a/app/Views/bag/dashboard_blend_inner.php +++ b/app/Views/bag/dashboard_blend_inner.php @@ -110,7 +110,7 @@ $notices = [ | · - +
diff --git a/app/Views/bag/dashboard_blend_lite_inner.php b/app/Views/bag/dashboard_blend_lite_inner.php index aabbf3d..088ef86 100644 --- a/app/Views/bag/dashboard_blend_lite_inner.php +++ b/app/Views/bag/dashboard_blend_lite_inner.php @@ -91,7 +91,7 @@ $notices = [ | · - + diff --git a/app/Views/bag/dashboard_portal.php b/app/Views/bag/dashboard_portal.php new file mode 100644 index 0000000..7b277a5 --- /dev/null +++ b/app/Views/bag/dashboard_portal.php @@ -0,0 +1,151 @@ + +
+ +
+
+

안녕하세요.

+

+

+
+ 아이디
최근접속 +

+ +
+ +
+

봉투 재고 총량

+

+

· 품목

+
+ +
+

주문 접수(정상)

+

+

전화·지정판매소 주문 누계

+
+ +
+

승인 대기

+

+

회원 가입 승인 요청

+
+
+ +
+ + +
+

재고 구성

+
+
+
+
+
    + +
  • + + % +
  • + +
+
+
+ + + + +
+

재고 적은 품목

+
+ +
+
+ + +
+
+
+
+
+ +
+
+ + + + +
+

최근 처리 내역

+
    + +
  • + + +
  • + +
+
+ +
+ + +
+

자주 가는 화면

+ +
+
diff --git a/app/Views/bag/inventory_inquiry.php b/app/Views/bag/inventory_inquiry.php index c3d2dbb..5b04138 100644 --- a/app/Views/bag/inventory_inquiry.php +++ b/app/Views/bag/inventory_inquiry.php @@ -142,7 +142,7 @@
-
diff --git a/app/Views/bag/lg_dashboard_dense.php b/app/Views/bag/lg_dashboard_dense.php index f18377f..eaeb41f 100644 --- a/app/Views/bag/lg_dashboard_dense.php +++ b/app/Views/bag/lg_dashboard_dense.php @@ -149,7 +149,7 @@ $notices = [ | 기준지자체 - + @@ -369,7 +369,7 @@ $notices = [
비중
-
일반 40%
+
일반 40%
스티커 30%
대형/특수 22%
diff --git a/app/Views/bag/lg_dashboard_simple.php b/app/Views/bag/lg_dashboard_simple.php index 5848251..bee092e 100644 --- a/app/Views/bag/lg_dashboard_simple.php +++ b/app/Views/bag/lg_dashboard_simple.php @@ -41,7 +41,7 @@ $lowStock = [ - diff --git a/app/Views/bag/manual.php b/app/Views/bag/manual.php index f0a73a3..3e61647 100644 --- a/app/Views/bag/manual.php +++ b/app/Views/bag/manual.php @@ -30,7 +30,7 @@ $nextSlug = ($pos !== false && $pos < count($slugs) - 1) ? $slugs[$pos + 1] : nu .manual-prose ol { list-style: decimal; } .manual-prose li { margin: 0.25rem 0; } .manual-prose li > ul, .manual-prose li > ol { margin-top: 0.25rem; } -.manual-prose a { color: #1c4e80; text-decoration: underline; } +.manual-prose a { color: #1a2b4b; text-decoration: underline; } .manual-prose a:hover { color: #2563eb; } .manual-prose strong { font-weight: 700; color: #111827; } .manual-prose blockquote { margin: 0.9rem 0; padding: 0.6rem 1rem; border-left: 4px solid #60a5fa; background: #eff6ff; color: #1e3a8a; border-radius: 0 6px 6px 0; } @@ -42,7 +42,7 @@ $nextSlug = ($pos !== false && $pos < count($slugs) - 1) ? $slugs[$pos + 1] : nu .manual-prose th { background: #e9ecef; font-weight: 700; color: #333; } .manual-prose tbody tr:nth-child(even) td { background: #f9fafb; } .manual-prose hr { margin: 1.6rem 0; border: 0; border-top: 1px solid #e5e7eb; } -.manual-toc a.active { background: #1c4e80; color: #fff; font-weight: 700; } +.manual-toc a.active { background: #1a2b4b; color: #fff; font-weight: 700; } @media print { .manual-toc, .manual-actions, .manual-nav { display: none !important; } .manual-layout { display: block !important; } diff --git a/app/Views/bag/number_lookup.php b/app/Views/bag/number_lookup.php index 2350942..e0b2073 100644 --- a/app/Views/bag/number_lookup.php +++ b/app/Views/bag/number_lookup.php @@ -93,8 +93,8 @@ $hasResult = $result !== null && ($result['ok'] ?? false); cursor: pointer; } .num-lookup-btn-primary { - border-color: #1c4e80; - background: linear-gradient(180deg, #2b6cb0 0%, #1c4e80 100%); + border-color: #243a5e; + background: linear-gradient(180deg, #2b6cb0 0%, #243a5e 100%); color: #fff; } .num-lookup-meta { diff --git a/app/Views/bag/waste_suibal_enterprise.php b/app/Views/bag/waste_suibal_enterprise.php index e56a33a..c596dd1 100644 --- a/app/Views/bag/waste_suibal_enterprise.php +++ b/app/Views/bag/waste_suibal_enterprise.php @@ -104,7 +104,7 @@ - diff --git a/app/Views/components/pager.php b/app/Views/components/pager.php index a4028f2..689b880 100644 --- a/app/Views/components/pager.php +++ b/app/Views/components/pager.php @@ -21,7 +21,7 @@ $pager->setSurroundCount(2); links() as $link): ?> - + diff --git a/app/Views/home/_dashboard_gov_portal_chrome_css.php b/app/Views/home/_dashboard_gov_portal_chrome_css.php new file mode 100644 index 0000000..7c8c299 --- /dev/null +++ b/app/Views/home/_dashboard_gov_portal_chrome_css.php @@ -0,0 +1,126 @@ + + :root { + --navy: #1a2b4b; + --navy-deep: #002b4e; + --blue: #0056b3; + --blue-ui: #007bff; + --blue-menu: #4a69bd; + --blue-light: #eef6ff; + --teal: #009688; + --bg: #f0f4f8; + --card: #fff; + --text: #444; + --text-dark: #222; + --muted: #888; + --border: #dde4ec; + --font-scale: 1; + } + .gov-portal-shell * { box-sizing: border-box; } + html.gov-portal-html { font-size: calc(14px * var(--font-scale)); -webkit-text-size-adjust: 100%; } + body.gov-portal-shell { + margin: 0; + font-family: 'Pretendard', 'Malgun Gothic', 'Apple SD Gothic Neo', 'Noto Sans KR', sans-serif; + font-size: 0.8125rem; + font-weight: 400; + line-height: 1.45; + letter-spacing: -0.01em; + color: var(--text); + background: var(--bg); + min-height: 100vh; + display: flex; + flex-direction: column; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + } + .gov-portal-shell .layout { display: flex; flex: 1; min-height: 0; } + + /* 좌측 사이드바 (대메뉴 클릭 → 소메뉴) */ + .gov-portal-shell .sidebar { + width: 188px; + flex-shrink: 0; + background: #fff; + border-right: 1px solid var(--border); + display: flex; + flex-direction: column; + font-size: 0.8125rem; + } + .gov-portal-shell .my-menu-hd { + background: var(--navy); + color: #fff; + padding: 0.55rem 0.7rem; + font-weight: 700; + font-size: 0.8125rem; + letter-spacing: -0.02em; + } + .gov-portal-shell .my-menu-list { list-style: none; padding: 0.375rem 0.25rem; margin: 0; flex: 1; overflow-y: auto; } + .gov-portal-shell .my-menu-list li { margin: 0.1875rem 0.375rem; } + .gov-portal-shell .my-menu-list a, + .gov-portal-shell .my-menu-list .menu-sub { + display: flex; + align-items: center; + gap: 0.375rem; + padding: 0.4375rem 0.625rem; + margin: 0; + border-radius: 10px; + border: 1px solid rgba(255, 255, 255, 0.22); + text-decoration: none; + font-size: 0.8125rem; + font-weight: 600; + line-height: 1.35; + letter-spacing: -0.02em; + box-sizing: border-box; + transition: filter 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease; + } + .gov-portal-shell .my-menu-list a { color: #fff; background: var(--blue-menu); } + .gov-portal-shell .my-menu-list a .menu-ico, + .gov-portal-shell .my-menu-list .menu-sub .menu-ico { font-size: 0.625rem; opacity: .9; width: 0.75rem; text-align: center; flex-shrink: 0; } + .gov-portal-shell .my-menu-list a:hover { filter: brightness(1.06); border-color: rgba(255, 255, 255, 0.35); } + .gov-portal-shell .my-menu-list a.active { + background: #3d5a9e; + font-weight: 700; + border-color: rgba(255, 255, 255, 0.4); + box-shadow: 0 1px 3px rgba(26, 43, 75, 0.12); + } + .gov-portal-shell .my-menu-list .menu-sub { background: var(--blue-light); color: var(--blue); font-size: 0.75rem; border-color: rgba(0, 86, 179, 0.18); } + .gov-portal-shell .sidebar-blocks { margin-top: auto; } + .gov-portal-shell .sb-teal { background: var(--teal); color: #fff; padding: 0.75rem 0.625rem; font-size: 0.6875rem; line-height: 1.5; letter-spacing: -0.02em; } + .gov-portal-shell .sb-teal i { font-size: 1.125rem; margin-bottom: 0.25rem; display: block; } + .gov-portal-shell .sb-gray { background: #4a5568; color: #fff; padding: 0.625rem; font-size: 0.6875rem; line-height: 1.45; } + .gov-portal-shell .sb-links { padding: 0.625rem; background: #f5f7fa; font-size: 0.6875rem; } + .gov-portal-shell .sb-links a { display: block; color: #555; text-decoration: none; padding: 0.1875rem 0; letter-spacing: -0.02em; font-weight: 600; } + .gov-portal-shell .sb-links a:hover { color: var(--blue-ui); } + + /* 본문 영역 */ + .gov-portal-shell .main { flex: 1; min-width: 0; overflow-y: auto; } + .gov-portal-shell .main.work-main { padding: 0.875rem 1rem 1.25rem; background: var(--bg); } + .gov-portal-shell .work-titlebar { + display: flex; align-items: center; gap: .5rem; + font-size: 1.05rem; font-weight: 800; color: var(--text-dark); + letter-spacing: -0.03em; margin: 0 0 0.75rem; + } + .gov-portal-shell .work-titlebar .tb-ico { color: var(--blue-ui); } + .gov-portal-shell .work-surface { + background: #fff; border: 1px solid var(--border); border-radius: 12px; + box-shadow: 0 1px 3px rgba(26,43,75,.06), 0 2px 8px rgba(26,43,75,.04); + padding: 1rem 1.1rem; + } + .gov-portal-shell .work-flash { margin-bottom: 0.75rem; padding: 0.6rem 0.9rem; border-radius: 8px; font-size: 0.8125rem; } + .gov-portal-shell .work-flash.ok { background: #ecfdf5; border: 1px solid #a7f3d0; color: #065f46; } + .gov-portal-shell .work-flash.err { background: #fef2f2; border: 1px solid #fecaca; color: #991b1b; } + .gov-portal-shell .portal-footer { + background: #eef2f7; border-top: 1px solid var(--border); + padding: 0.3rem 1rem; font-size: 0.6875rem; color: var(--muted); + display: flex; justify-content: space-between; align-items: center; + } + + @media (max-width: 1024px) { + .gov-portal-shell .layout { flex-direction: column; } + .gov-portal-shell .sidebar { width: 100%; border-right: none; border-bottom: 1px solid var(--border); } + .gov-portal-shell .my-menu-list { display: flex; flex-wrap: wrap; } + } diff --git a/app/Views/home/dashboard.php b/app/Views/home/dashboard.php index d8e85f3..62e7d9a 100644 --- a/app/Views/home/dashboard.php +++ b/app/Views/home/dashboard.php @@ -15,7 +15,7 @@ tailwind.config = { colors: { 'title-bar': '#2c3e50', 'control-panel': '#f8f9fa', - 'btn-search': '#1c4e80', + 'btn-search': '#243a5e', 'btn-exit': '#d9534f', } } diff --git a/app/Views/welcome_message.php b/app/Views/welcome_message.php index ed4ab00..c64aff8 100644 --- a/app/Views/welcome_message.php +++ b/app/Views/welcome_message.php @@ -3,48 +3,63 @@ -종량제 시스템 +종량제 물류시스템 - - + + - + - -
- -