gov-portal 디자인을 시스템 전체에 적용한다.
- 사이트 업무 페이지: 공통 셸 bag/layout/portal(헤더+대메뉴 클릭+좌측 사이드바 소메뉴) - 관리자 페이지: admin/layout 을 동일 포털 셸로 재작성(관리자 메뉴 트리, 폴백) - 메인(/): gov-portal 대시보드, 종량제 실데이터만(재고/주문/승인/활동로그) - 로그인/회원가입/2차인증/TOTP: 공통 auth/_shell 로 통일, 사이트 공통 로고 - 버튼색 통일: btn-search 등 주요 버튼을 #243a5e(메뉴바 네이비보다 살짝 밝게), 밝은 파랑 채움 버튼(#2b4c8c/#1e548a)도 동일 색으로 - gov_portal_nav_context() 임의 메뉴 트리 수용, 업무 셸은 실제 bag/* 링크 유지 - Admin\Menu 권한거부 리다이렉트 admin/dashboard(404) → admin 수정 - E2E redesign.spec.js 추가, 기능 무변경 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -23,7 +23,7 @@ if (isset($pager) && $pager !== null) {
|
||||
<div class="flex items-center gap-2">
|
||||
<button type="button" onclick="window.print()" class="no-print rounded border border-gray-300 px-3 py-1 text-sm text-gray-600 hover:bg-gray-50">인쇄</button>
|
||||
<?php if ($canManage): ?>
|
||||
<a href="<?= base_url('admin/code-details/' . (int) $kind->ck_idx . '/create') ?>" class="rounded border border-transparent bg-[#1c4e80] px-3 py-1.5 text-sm text-white shadow hover:opacity-90">세부코드 등록</a>
|
||||
<a href="<?= base_url('admin/code-details/' . (int) $kind->ck_idx . '/create') ?>" class="rounded border border-transparent bg-[#243a5e] px-3 py-1.5 text-sm text-white shadow hover:opacity-90">세부코드 등록</a>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -19,7 +19,7 @@ $detailColCount = 7 + ($canManageDetails ? 1 : 0);
|
||||
<h3 class="text-base font-bold text-gray-700">기본코드 종류</h3>
|
||||
<div class="flex flex-wrap items-center gap-2 text-xs sm:text-sm">
|
||||
<?php if ($canManageKinds): ?>
|
||||
<a href="<?= base_url('admin/code-kinds/create') ?>" class="inline-flex items-center rounded bg-[#1c4e80] px-3 py-1.5 text-white shadow hover:opacity-90">기본코드 등록</a>
|
||||
<a href="<?= base_url('admin/code-kinds/create') ?>" class="inline-flex items-center rounded bg-[#243a5e] px-3 py-1.5 text-white shadow hover:opacity-90">기본코드 등록</a>
|
||||
<?php else: ?>
|
||||
<span class="text-gray-500">코드 종류 등록·수정은 super admin·본부 관리자만 가능합니다.</span>
|
||||
<?php endif; ?>
|
||||
@@ -81,7 +81,7 @@ $detailColCount = 7 + ($canManageDetails ? 1 : 0);
|
||||
<?php endif; ?>
|
||||
</h3>
|
||||
<?php if ($canManageDetails && $selectedKind !== null): ?>
|
||||
<a href="<?= base_url('admin/code-details/' . (int) $selectedKind->ck_idx . '/create') ?>" class="inline-flex items-center rounded bg-[#1c4e80] px-3 py-1.5 text-white shadow hover:opacity-90 text-sm">세부코드 등록</a>
|
||||
<a href="<?= base_url('admin/code-details/' . (int) $selectedKind->ck_idx . '/create') ?>" class="inline-flex items-center rounded bg-[#243a5e] px-3 py-1.5 text-white shadow hover:opacity-90 text-sm">세부코드 등록</a>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -110,7 +110,7 @@ $notices = [
|
||||
<span><i class="fa-regular fa-calendar mr-0.5"></i><?= date('Y-m-d (D) H:i') ?></span>
|
||||
<span class="text-gray-300">|</span>
|
||||
<span><?= esc($lgLabel) ?> · <strong class="text-gray-800"><?= esc($mbName) ?></strong></span>
|
||||
<button type="button" class="bg-[#2b4c8c] text-white px-2 py-0.5 rounded text-[11px]" onclick="location.reload()"><i class="fa-solid fa-rotate mr-0.5"></i>새로고침</button>
|
||||
<button type="button" class="bg-[#243a5e] text-white px-2 py-0.5 rounded text-[11px]" onclick="location.reload()"><i class="fa-solid fa-rotate mr-0.5"></i>새로고침</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -91,7 +91,7 @@ $notices = [
|
||||
<span><i class="fa-regular fa-calendar mr-0.5"></i><?= date('Y-m-d (D) H:i') ?></span>
|
||||
<span class="text-gray-300">|</span>
|
||||
<span><?= esc($lgLabel) ?> · <strong class="text-gray-800"><?= esc($mbName) ?></strong></span>
|
||||
<button type="button" class="bg-[#2b4c8c] text-white px-2 py-0.5 rounded text-[11px]" onclick="location.reload()"><i class="fa-solid fa-rotate mr-0.5"></i>새로고침</button>
|
||||
<button type="button" class="bg-[#243a5e] text-white px-2 py-0.5 rounded text-[11px]" onclick="location.reload()"><i class="fa-solid fa-rotate mr-0.5"></i>새로고침</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
151
app/Views/bag/dashboard_portal.php
Normal file
151
app/Views/bag/dashboard_portal.php
Normal file
@@ -0,0 +1,151 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* 메인(/) gov-portal 디자인 대시보드 — 종량제 실데이터만 표시.
|
||||
*
|
||||
* @var string $lgLabel
|
||||
* @var string $mbName
|
||||
* @var string $mbId
|
||||
* @var string $levelName
|
||||
* @var int $totalQty
|
||||
* @var int $itemCount
|
||||
* @var int $orderCount
|
||||
* @var int $pendingApprovals
|
||||
* @var array $stockMix
|
||||
* @var array $lowStock
|
||||
* @var array $recentActivity
|
||||
*/
|
||||
$stockMix = is_array($stockMix ?? null) ? $stockMix : [];
|
||||
$lowStock = is_array($lowStock ?? null) ? $lowStock : [];
|
||||
$recentActivity = is_array($recentActivity ?? null) ? $recentActivity : [];
|
||||
|
||||
// 도넛 conic-gradient 누적 계산
|
||||
$donutStops = [];
|
||||
$acc = 0;
|
||||
foreach ($stockMix as $m) {
|
||||
$start = $acc;
|
||||
$acc += (int) $m['value'];
|
||||
$donutStops[] = $m['color'] . ' ' . $start . '% ' . $acc . '%';
|
||||
}
|
||||
$donutCss = $donutStops !== [] ? implode(', ', $donutStops) : '#e5e7eb 0% 100%';
|
||||
?>
|
||||
<div class="space-y-4">
|
||||
<!-- 프로필 + KPI -->
|
||||
<section class="grid grid-cols-1 lg:grid-cols-4 gap-4">
|
||||
<div class="rounded-xl bg-slate-700 text-white p-4 shadow-sm">
|
||||
<p class="text-xs text-white/70">안녕하세요.</p>
|
||||
<p class="text-lg font-bold mt-1"><?= esc($mbName) ?>님</p>
|
||||
<p class="text-[11px] text-white/70 mt-1 leading-relaxed">
|
||||
<?= esc($levelName) ?><?= $lgLabel !== '' ? ' · ' . esc($lgLabel) : '' ?><br/>
|
||||
아이디 <?= esc($mbId) ?><br/>최근접속 <?= date('Y.m.d H:i') ?>
|
||||
</p>
|
||||
<div class="flex gap-1.5 mt-3">
|
||||
<a href="<?= base_url('bag/manual') ?>" class="text-[11px] px-2 py-1 rounded bg-white/10 hover:bg-white/20 border border-white/30">매뉴얼</a>
|
||||
<a href="<?= base_url('logout') ?>" class="text-[11px] px-2 py-1 rounded bg-white/10 hover:bg-white/20 border border-white/30">로그아웃</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="rounded-xl bg-white border border-gray-200 p-4 shadow-sm">
|
||||
<p class="text-xs text-gray-500"><i class="fa-solid fa-boxes-stacked text-blue-600 mr-1"></i>봉투 재고 총량</p>
|
||||
<p class="text-2xl font-bold text-gray-900 mt-1"><?= number_format($totalQty) ?><span class="text-sm font-medium text-gray-400 ml-1">개</span></p>
|
||||
<p class="text-[11px] text-gray-500 mt-1"><?= esc($lgLabel !== '' ? $lgLabel : '전체') ?> · 품목 <?= (int) $itemCount ?>종</p>
|
||||
</div>
|
||||
|
||||
<div class="rounded-xl bg-white border border-gray-200 p-4 shadow-sm">
|
||||
<p class="text-xs text-gray-500"><i class="fa-solid fa-receipt text-sky-600 mr-1"></i>주문 접수(정상)</p>
|
||||
<p class="text-2xl font-bold text-sky-700 mt-1"><?= (int) $orderCount ?><span class="text-sm font-medium text-gray-400 ml-1">건</span></p>
|
||||
<p class="text-[11px] text-gray-500 mt-1">전화·지정판매소 주문 누계</p>
|
||||
</div>
|
||||
|
||||
<div class="rounded-xl bg-white border border-gray-200 p-4 shadow-sm">
|
||||
<p class="text-xs text-gray-500"><i class="fa-solid fa-user-check text-violet-600 mr-1"></i>승인 대기</p>
|
||||
<p class="text-2xl font-bold text-violet-700 mt-1"><?= (int) $pendingApprovals ?><span class="text-sm font-medium text-gray-400 ml-1">명</span></p>
|
||||
<p class="text-[11px] text-gray-500 mt-1">회원 가입 승인 요청</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="grid grid-cols-1 lg:grid-cols-3 gap-4">
|
||||
<?php if ($stockMix !== []): ?>
|
||||
<!-- 재고 구성 -->
|
||||
<div class="rounded-xl bg-white border border-gray-200 p-4 shadow-sm">
|
||||
<h2 class="text-sm font-bold text-gray-900 mb-3"><i class="fa-solid fa-chart-pie text-blue-600 mr-1"></i>재고 구성</h2>
|
||||
<div class="flex items-center gap-4">
|
||||
<div class="w-20 h-20 rounded-full shrink-0" style="background: conic-gradient(<?= $donutCss ?>);">
|
||||
<div class="w-10 h-10 bg-white rounded-full mx-auto" style="margin-top:1.25rem;"></div>
|
||||
</div>
|
||||
<ul class="text-[11px] text-gray-600 space-y-1 min-w-0">
|
||||
<?php foreach ($stockMix as $m): ?>
|
||||
<li class="flex items-center gap-2">
|
||||
<span class="inline-block w-2.5 h-2.5 rounded-full shrink-0" style="background-color: <?= esc($m['color'], 'attr') ?>"></span>
|
||||
<span class="truncate"><?= esc($m['name']) ?> <?= (int) $m['value'] ?>%</span>
|
||||
</li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($lowStock !== []): ?>
|
||||
<!-- 부족 재고 -->
|
||||
<div class="rounded-xl bg-white border border-gray-200 p-4 shadow-sm">
|
||||
<h2 class="text-sm font-bold text-gray-900 mb-3"><i class="fa-solid fa-box-open text-amber-600 mr-1"></i>재고 적은 품목</h2>
|
||||
<div class="space-y-2">
|
||||
<?php foreach ($lowStock as $item): ?>
|
||||
<div>
|
||||
<div class="flex justify-between text-[11px] text-gray-600 mb-1">
|
||||
<span class="truncate"><?= esc($item['name']) ?></span>
|
||||
<span class="shrink-0 ml-2"><?= number_format((int) $item['qty']) ?>개</span>
|
||||
</div>
|
||||
<div class="h-2 rounded bg-gray-100 overflow-hidden">
|
||||
<div class="h-full rounded bg-amber-500" style="width: <?= (int) $item['percent'] ?>%"></div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($recentActivity !== []): ?>
|
||||
<!-- 최근 활동 (activity_log) -->
|
||||
<div class="rounded-xl bg-white border border-gray-200 p-4 shadow-sm">
|
||||
<h2 class="text-sm font-bold text-gray-900 mb-3"><i class="fa-solid fa-clock-rotate-left text-emerald-600 mr-1"></i>최근 처리 내역</h2>
|
||||
<ul class="space-y-2">
|
||||
<?php foreach ($recentActivity as $ev): ?>
|
||||
<li class="flex items-start gap-2 text-[12px]">
|
||||
<span class="text-[11px] font-semibold text-gray-400 shrink-0 w-20"><?= esc($ev['time']) ?></span>
|
||||
<span class="text-gray-700"><?= esc($ev['text']) ?></span>
|
||||
</li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</section>
|
||||
|
||||
<!-- 자주 가는 화면 (실제 메뉴 링크) -->
|
||||
<section class="rounded-xl bg-white border border-gray-200 p-4 shadow-sm">
|
||||
<h2 class="text-sm font-bold text-gray-900 mb-3"><i class="fa-solid fa-location-arrow text-blue-600 mr-1"></i>자주 가는 화면</h2>
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-2">
|
||||
<?php
|
||||
$links = [
|
||||
['bag/inventory', '창고 재고 조회', '품목별 현재 재고', 'fa-boxes-stacked', 'emerald'],
|
||||
['bag/order/create', '발주 등록', '봉투 발주·구매신청', 'fa-cart-shopping', 'sky'],
|
||||
['bag/flow', '봉투 수불 현황', '입고·출고 내역', 'fa-arrow-right-arrow-left', 'orange'],
|
||||
['bag/sales', '판매 관리', '판매/반품 내역', 'fa-receipt', 'indigo'],
|
||||
['bag/reports/daily-summary', '일계표', '일일 판매 요약', 'fa-table-list', 'violet'],
|
||||
['bag/manual', '사용자 매뉴얼', '업무별 사용 안내', 'fa-book', 'slate'],
|
||||
];
|
||||
foreach ($links as [$path, $label, $desc, $icon, $c]):
|
||||
?>
|
||||
<a href="<?= base_url($path) ?>" class="group flex items-center gap-3 px-3 py-2 rounded border border-gray-200 hover:border-blue-500 hover:bg-blue-50/40 transition">
|
||||
<div class="h-8 w-8 rounded-full bg-<?= $c ?>-50 text-<?= $c ?>-600 flex items-center justify-center shrink-0">
|
||||
<i class="fa-solid <?= $icon ?>"></i>
|
||||
</div>
|
||||
<div class="min-w-0">
|
||||
<p class="text-xs font-semibold text-gray-900 group-hover:text-blue-800"><?= esc($label) ?></p>
|
||||
<p class="text-[11px] text-gray-500 truncate"><?= esc($desc) ?></p>
|
||||
</div>
|
||||
</a>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
@@ -142,7 +142,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<button class="bg-[#1e548a] hover:bg-blue-900 text-white px-4 py-1.5 rounded text-sm font-medium flex items-center gap-1 transition-colors">
|
||||
<button class="bg-[#243a5e] hover:brightness-110 text-white px-4 py-1.5 rounded text-sm font-medium flex items-center gap-1 transition-colors">
|
||||
<i class="fa-solid fa-magnifying-glass"></i> 검색
|
||||
</button>
|
||||
<button class="bg-white border border-[#2e7d32] text-[#2e7d32] hover:bg-green-50 px-4 py-1.5 rounded text-sm font-medium flex items-center gap-1 transition-colors">
|
||||
|
||||
@@ -29,9 +29,9 @@ tailwind.config = {
|
||||
fontFamily: { sans: ['"Malgun Gothic"', '"Noto Sans KR"', 'sans-serif'] },
|
||||
colors: {
|
||||
'system-header': '#ffffff',
|
||||
'title-bar': '#2c3e50',
|
||||
'title-bar': '#1a2b4b',
|
||||
'control-panel': '#f8f9fa',
|
||||
'btn-search': '#1c4e80',
|
||||
'btn-search': '#243a5e',
|
||||
'btn-excel-border': '#28a745',
|
||||
'btn-excel-text': '#28a745',
|
||||
'btn-print-border': '#ced4da',
|
||||
|
||||
169
app/Views/bag/layout/portal.php
Normal file
169
app/Views/bag/layout/portal.php
Normal file
@@ -0,0 +1,169 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* 사이트 업무 페이지 공통 셸 — gov-portal 디자인 적용판.
|
||||
* 헤더 + 대메뉴(클릭) + 좌측 사이드바(소메뉴) + 본문($content).
|
||||
* 본문은 기존 Tailwind 마크업을 그대로 쓰므로 Tailwind CDN·config·data-table 스타일을 함께 로드한다.
|
||||
*
|
||||
* @var string $title
|
||||
* @var string $content (이스케이프 없이 출력되는 본문 HTML)
|
||||
* @var bool $bare true면 work-surface 카드/제목바 없이 본문을 그대로 출력(대시보드용)
|
||||
*/
|
||||
helper('admin');
|
||||
$bare = ! empty($bare);
|
||||
|
||||
$gov = gov_portal_nav_context(false); // 업무 셸: 실제 bag/* 링크 유지(코드관리 포털 remap 안 함)
|
||||
$govActiveChildHref = gov_portal_nav_match_path($gov['currentPath']);
|
||||
|
||||
$navPartial = [
|
||||
'govNavItems' => $gov['navItems'],
|
||||
'govNavJson' => $gov['navJson'],
|
||||
'govActiveParentIdx' => $gov['activeParentIdx'],
|
||||
'govCurrentPath' => gov_portal_nav_match_path($gov['currentPath']),
|
||||
'govDashboardAliases' => $gov['dashboardAliases'],
|
||||
'govActiveChildHref' => $govActiveChildHref,
|
||||
];
|
||||
|
||||
$mbLevel = (int) session()->get('mb_level');
|
||||
$mbName = (string) (session()->get('mb_name') ?? '담당자');
|
||||
$levelName = config(\Config\Roles::class)->getLevelName($mbLevel);
|
||||
$isAdmin = ($mbLevel === \Config\Roles::LEVEL_SUPER_ADMIN || $mbLevel === \Config\Roles::LEVEL_LOCAL_ADMIN);
|
||||
|
||||
$effectiveLgIdx = admin_effective_lg_idx();
|
||||
$lgLabel = '';
|
||||
if ($effectiveLgIdx) {
|
||||
$lgRow = model(\App\Models\LocalGovernmentModel::class)->find($effectiveLgIdx);
|
||||
$lgLabel = $lgRow ? (string) $lgRow->lg_name : '';
|
||||
}
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="ko" class="gov-portal-html">
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
|
||||
<title><?= esc($title ?? '종량제 시스템') ?></title>
|
||||
<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"/>
|
||||
<script src="https://cdn.tailwindcss.com?plugins=forms,container-queries"></script>
|
||||
<script>
|
||||
tailwind.config = {
|
||||
theme: {
|
||||
extend: {
|
||||
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',
|
||||
},
|
||||
fontSize: { 'xxs': '0.65rem' }
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<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; }
|
||||
.data-table th, .data-table td { border: 1px solid #ccc; padding: 4px 8px; white-space: nowrap; font-size: 13px; }
|
||||
.data-table th { background-color: #e9ecef; text-align: center; vertical-align: middle; font-weight: bold; color: #333; }
|
||||
.data-table tbody tr:nth-child(even) td { background-color: #f9f9f9; }
|
||||
.data-table tbody tr:hover td { background-color: #e6f7ff !important; }
|
||||
@media print {
|
||||
.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; }
|
||||
.print-header { display: block !important; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="gov-portal-shell">
|
||||
<header class="portal-header">
|
||||
<div class="portal-header-inner">
|
||||
<?= view('home/_dashboard_gov_portal_brand', ['brandHref' => base_url('/')]) ?>
|
||||
<?= view('home/_dashboard_gov_portal_topnav_click', $navPartial) ?>
|
||||
<div class="portal-header-utils" style="display:flex;align-items:center;gap:.5rem;">
|
||||
<span class="user-line">
|
||||
<?php if ($lgLabel !== ''): ?><strong><?= esc($lgLabel) ?></strong> · <?php endif; ?>
|
||||
<?= esc($levelName) ?> · <?= esc($mbName) ?>님
|
||||
</span>
|
||||
<?php if ($isAdmin): ?>
|
||||
<a href="<?= base_url('admin') ?>" 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-gear"></i> 관리자
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
<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 (! $bare && ! empty($title)): ?>
|
||||
<h1 class="work-titlebar"><i class="fa-solid fa-folder-open 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 ($bare): ?>
|
||||
<?= $content ?>
|
||||
<?php else: ?>
|
||||
<div class="work-surface">
|
||||
<?= $content ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<footer class="portal-footer">
|
||||
<span>종량제 시스템</span>
|
||||
<span><?= date('Y.m.d (D) H:i') ?></span>
|
||||
</footer>
|
||||
|
||||
<?= view('home/_dashboard_gov_portal_nav_script_base', $navPartial) ?>
|
||||
<script>
|
||||
(() => {
|
||||
// 표의 '번호' 컬럼 역순 자동 채번 (기존 사이트 레이아웃 계승)
|
||||
const normalize = (s) => String(s || '').replace(/\s+/g, '').trim();
|
||||
const renumberTable = (table) => {
|
||||
const headRow = table.querySelector('thead tr');
|
||||
if (!headRow) return;
|
||||
const headers = Array.from(headRow.querySelectorAll('th'));
|
||||
const numberCol = headers.findIndex((th) => normalize(th.textContent) === '번호');
|
||||
if (numberCol < 0) return;
|
||||
const body = table.querySelector('tbody');
|
||||
if (!body) return;
|
||||
const rows = Array.from(body.querySelectorAll(':scope > tr')).filter((tr) => {
|
||||
const cells = tr.querySelectorAll('td');
|
||||
if (cells.length === 0) return false;
|
||||
if (cells.length === 1 && Number(cells[0].getAttribute('colspan') || '1') > 1) return false;
|
||||
return true;
|
||||
});
|
||||
let no = rows.length;
|
||||
rows.forEach((tr) => {
|
||||
const cells = tr.querySelectorAll('td');
|
||||
if (cells[numberCol]) cells[numberCol].textContent = String(no--);
|
||||
});
|
||||
};
|
||||
const run = () => document.querySelectorAll('table').forEach(renumberTable);
|
||||
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', run, { once: true });
|
||||
else run();
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -103,7 +103,7 @@ $mbName = session()->get('mb_name') ?? '담당자';
|
||||
<input type="text" readonly value="<?= date('Y.m.d') ?>" class="border border-gray-300 px-2 py-1 rounded w-28 shadow-sm">
|
||||
<span class="text-gray-500">|</span>
|
||||
<span class="text-gray-600">지자체 <strong class="text-gray-800"><?= esc($lgLabel) ?></strong></span>
|
||||
<button type="button" class="bg-[#2b4c8c] hover:bg-blue-800 text-white px-3 py-1 rounded text-xs font-medium shadow flex items-center gap-1">
|
||||
<button type="button" class="bg-[#243a5e] hover:brightness-110 text-white px-3 py-1 rounded text-xs font-medium shadow flex items-center gap-1">
|
||||
<i class="fa-solid fa-rotate"></i> 새로고침
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -149,7 +149,7 @@ $notices = [
|
||||
<span><i class="fa-regular fa-calendar mr-0.5"></i><?= date('Y-m-d (D) H:i') ?></span>
|
||||
<span class="text-gray-300">|</span>
|
||||
<span>기준지자체 <strong class="text-gray-800"><?= esc($lgLabel) ?></strong></span>
|
||||
<button type="button" class="bg-[#2b4c8c] text-white px-2 py-0.5 rounded text-[11px]"><i class="fa-solid fa-rotate mr-0.5"></i>새로고침</button>
|
||||
<button type="button" class="bg-[#243a5e] text-white px-2 py-0.5 rounded text-[11px]"><i class="fa-solid fa-rotate mr-0.5"></i>새로고침</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -369,7 +369,7 @@ $notices = [
|
||||
<div class="absolute inset-2 rounded-full bg-white flex items-center justify-center text-[10px] font-bold text-gray-700">비중</div>
|
||||
</div>
|
||||
<div class="text-[10px] text-gray-600 space-y-0.5">
|
||||
<div><span class="inline-block w-2 h-2 rounded-full bg-[#2b4c8c] mr-1"></span>일반 40%</div>
|
||||
<div><span class="inline-block w-2 h-2 rounded-full bg-[#243a5e] mr-1"></span>일반 40%</div>
|
||||
<div><span class="inline-block w-2 h-2 rounded-full bg-emerald-500 mr-1"></span>스티커 30%</div>
|
||||
<div><span class="inline-block w-2 h-2 rounded-full bg-amber-500 mr-1"></span>대형/특수 22%</div>
|
||||
</div>
|
||||
|
||||
@@ -41,7 +41,7 @@ $lowStock = [
|
||||
<i class="fa-regular fa-calendar mr-1 text-gray-500"></i><?= date('Y.m.d (D)') ?>
|
||||
</div>
|
||||
</div>
|
||||
<button type="button" class="inline-flex items-center justify-center px-3 py-1.5 rounded bg-blue-600 hover:bg-blue-700 text-white text-xs font-medium shadow">
|
||||
<button type="button" class="inline-flex items-center justify-center px-3 py-1.5 rounded bg-btn-search hover:brightness-110 text-white text-xs font-medium shadow">
|
||||
<i class="fa-solid fa-rotate mr-1"></i> 새로고침
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -104,7 +104,7 @@
|
||||
<option>북구</option>
|
||||
</select>
|
||||
</div>
|
||||
<button type="button" class="bg-[#2b4c8c] hover:bg-blue-800 text-white px-4 py-1.5 rounded text-sm font-medium shadow flex items-center gap-1">
|
||||
<button type="button" class="bg-[#243a5e] hover:brightness-110 text-white px-4 py-1.5 rounded text-sm font-medium shadow flex items-center gap-1">
|
||||
<i class="fa-solid fa-magnifying-glass"></i> 검색
|
||||
</button>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user