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:
70
app/Views/auth/_shell.php
Normal file
70
app/Views/auth/_shell.php
Normal file
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* 인증 페이지 공통 셸 — gov-portal 디자인.
|
||||
* 사용: 자식 뷰 상단에서 $this->extend('auth/_shell'),
|
||||
* 섹션 'heading'(카드 제목)·'content'(본문) 정의.
|
||||
* 선택 변수: $subtitle(카드 헤더 소제목), $cardMax(예: 'max-w-lg', 기본 'max-w-md')
|
||||
*/
|
||||
$cardMax = $cardMax ?? 'max-w-md';
|
||||
$subtitle = $subtitle ?? '종량제 쓰레기봉투 물류시스템';
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="ko">
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
|
||||
<title><?= esc($pageTitle ?? '종량제 시스템') ?></title>
|
||||
<script src="https://cdn.tailwindcss.com?plugins=forms,container-queries"></script>
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/orioncactus/pretendard@v1.3.9/dist/web/static/pretendard.min.css"/>
|
||||
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" rel="stylesheet"/>
|
||||
<script>
|
||||
tailwind.config = {
|
||||
theme: {
|
||||
extend: {
|
||||
fontFamily: { sans: ['Pretendard', '"Malgun Gothic"', '"Noto Sans KR"', 'sans-serif'] },
|
||||
colors: {
|
||||
'navy': '#1a2b4b', 'title-bar': '#1a2b4b', 'portal-bg': '#f0f4f8',
|
||||
'btn-search': '#243a5e', 'btn-exit': '#d9534f',
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style>body { -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; letter-spacing: -0.01em; }</style>
|
||||
</head>
|
||||
<body class="bg-portal-bg text-gray-700 flex flex-col min-h-screen font-sans antialiased">
|
||||
<header class="bg-navy text-white h-12 flex items-center justify-between px-4 shrink-0 shadow">
|
||||
<a href="<?= base_url() ?>" class="flex items-center gap-2 shrink-0 text-base font-bold tracking-tight hover:opacity-90" title="종량제 시스템">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" class="h-6 w-6 text-white shrink-0" aria-hidden="true" focusable="false">
|
||||
<path fill="currentColor" d="M9 3a1 1 0 00-1 1v1H5.75a.75.75 0 000 1.5h12.5a.75.75 0 000-1.5H16V4a1 1 0 00-1-1H9zm9 4H6v11a2 2 0 002 2h8a2 2 0 002-2V7zM10 9a.75.75 0 01.75.75v6a.75.75 0 01-1.5 0v-6A.75.75 0 0110 9zm4 0a.75.75 0 01.75.75v6a.75.75 0 01-1.5 0v-6A.75.75 0 0114 9z"/>
|
||||
</svg>
|
||||
<span class="whitespace-nowrap">종량제 시스템</span>
|
||||
</a>
|
||||
</header>
|
||||
|
||||
<main class="flex-grow p-6 flex items-center justify-center">
|
||||
<section class="w-full <?= esc($cardMax) ?> bg-white border border-[#dde4ec] rounded-2xl shadow-[0_2px_12px_rgba(26,43,75,0.08)] overflow-hidden">
|
||||
<div class="bg-gradient-to-br from-navy to-[#007bff] text-white px-6 py-5">
|
||||
<p class="text-xs text-white/70"><?= esc($subtitle) ?></p>
|
||||
<h1 class="text-lg font-bold mt-0.5"><?= $this->renderSection('heading') ?></h1>
|
||||
</div>
|
||||
<div class="p-6">
|
||||
<?php if (session()->getFlashdata('error')): ?>
|
||||
<div class="mb-4 p-3 rounded-lg bg-red-50 text-red-700 text-sm" role="alert"><?= esc(session()->getFlashdata('error')) ?></div>
|
||||
<?php endif; ?>
|
||||
<?php if (session()->getFlashdata('errors')): ?>
|
||||
<div class="mb-4 p-3 rounded-lg bg-red-50 text-red-700 text-sm space-y-1" role="alert">
|
||||
<?php foreach (session()->getFlashdata('errors') as $error): ?><p><?= esc($error) ?></p><?php endforeach; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php if (session()->getFlashdata('success')): ?>
|
||||
<div class="mb-4 p-3 rounded-lg bg-green-50 text-green-700 text-sm" role="alert"><?= esc(session()->getFlashdata('success')) ?></div>
|
||||
<?php endif; ?>
|
||||
<?= $this->renderSection('content') ?>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
<footer class="bg-[#eef2f7] border-t border-[#dde4ec] px-4 py-1.5 text-xs text-gray-500 shrink-0 text-center">종량제 물류시스템</footer>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,72 +1,21 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ko">
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
|
||||
<title>로그인 - 종량제 시스템</title>
|
||||
<script src="https://cdn.tailwindcss.com?plugins=forms,container-queries"></script>
|
||||
<style data-purpose="global-font-scale">html{font-size:18px}.app-brand,.app-brand *{font-size:16px}</style>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@300;400;500;700&display=swap" rel="stylesheet"/>
|
||||
<script>
|
||||
tailwind.config = {
|
||||
theme: {
|
||||
extend: {
|
||||
fontFamily: { sans: ['"Malgun Gothic"', '"Noto Sans KR"', 'sans-serif'] },
|
||||
colors: {
|
||||
'system-header': '#ffffff',
|
||||
'title-bar': '#2c3e50',
|
||||
'control-panel': '#f8f9fa',
|
||||
'btn-search': '#1c4e80',
|
||||
'btn-exit': '#d9534f',
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style>body { -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; }</style>
|
||||
</head>
|
||||
<body class="bg-gray-100 text-gray-800 flex flex-col h-screen font-sans antialiased">
|
||||
<header class="bg-white border-b border-gray-300 h-12 flex items-center justify-between px-4 shrink-0">
|
||||
<a href="<?= base_url() ?>" class="flex items-center gap-2 shrink-0 text-base font-semibold text-gray-800 tracking-tight hover:text-blue-600" title="종량제 시스템">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" class="h-6 w-6 text-blue-900 translate-y-[1px]" aria-hidden="true" focusable="false">
|
||||
<path fill="currentColor" d="M9 3a1 1 0 00-1 1v1H5.75a.75.75 0 000 1.5h12.5a.75.75 0 000-1.5H16V4a1 1 0 00-1-1H9zm9 4H6v11a2 2 0 002 2h8a2 2 0 002-2V7zM10 9a.75.75 0 01.75.75v6a.75.75 0 01-1.5 0v-6A.75.75 0 0110 9zm4 0a.75.75 0 01.75.75v6a.75.75 0 01-1.5 0v-6A.75.75 0 0114 9z"/>
|
||||
</svg>
|
||||
<span class="whitespace-nowrap">종량제 시스템</span>
|
||||
</a>
|
||||
</header>
|
||||
<div class="bg-title-bar text-white px-4 py-2 text-sm font-medium shrink-0">
|
||||
로그인
|
||||
</div>
|
||||
<?php if (session()->getFlashdata('success')): ?>
|
||||
<div class="mx-4 mt-2 p-3 rounded-lg bg-green-50 text-green-700 text-sm" role="alert"><?= esc(session()->getFlashdata('success')) ?></div>
|
||||
<?php endif; ?>
|
||||
<?php if (session()->getFlashdata('error')): ?>
|
||||
<div class="mx-4 mt-2 p-3 rounded-lg bg-red-50 text-red-700 text-sm" role="alert"><?= esc(session()->getFlashdata('error')) ?></div>
|
||||
<?php endif; ?>
|
||||
<?php if (session()->getFlashdata('errors')): ?>
|
||||
<div class="mx-4 mt-2 p-3 rounded-lg bg-red-50 text-red-700 text-sm space-y-1" role="alert">
|
||||
<?php foreach (session()->getFlashdata('errors') as $error): ?><p><?= esc($error) ?></p><?php endforeach; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<main class="flex-grow bg-control-panel border-b border-gray-300 p-6 flex items-center justify-center">
|
||||
<section class="w-full max-w-md bg-white border border-gray-300 rounded shadow-sm p-6">
|
||||
<form action="<?= base_url('login') ?>" method="POST" class="space-y-4">
|
||||
<?= csrf_field() ?>
|
||||
<div>
|
||||
<label class="block text-sm font-bold text-gray-700 mb-1" for="login_id">아이디</label>
|
||||
<input class="block w-full border border-gray-300 rounded px-3 py-2 text-sm focus:ring-blue-500 focus:border-blue-500" id="login_id" name="login_id" type="text" placeholder="아이디" value="<?= esc(old('login_id')) ?>" autocomplete="username" autofocus/>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-bold text-gray-700 mb-1" for="password">비밀번호</label>
|
||||
<input class="block w-full border border-gray-300 rounded px-3 py-2 text-sm focus:ring-blue-500 focus:border-blue-500" id="password" name="password" type="password" placeholder="비밀번호" autocomplete="current-password"/>
|
||||
</div>
|
||||
<div class="flex gap-2 pt-2">
|
||||
<button type="submit" class="bg-btn-search text-white px-4 py-2 rounded-sm text-sm font-medium shadow hover:opacity-90 transition border border-transparent">로그인</button>
|
||||
<a href="<?= base_url('register') ?>" class="bg-white text-gray-700 border border-gray-300 px-4 py-2 rounded-sm text-sm shadow hover:bg-gray-50 transition">회원가입</a>
|
||||
</div>
|
||||
</form>
|
||||
</section>
|
||||
</main>
|
||||
<footer class="bg-gray-200 border-t border-gray-300 px-4 py-1 text-xs text-gray-600 shrink-0">종량제 시스템</footer>
|
||||
</body>
|
||||
</html>
|
||||
<?= $this->extend('auth/_shell') ?>
|
||||
|
||||
<?= $this->section('heading') ?>로그인<?= $this->endSection() ?>
|
||||
|
||||
<?= $this->section('content') ?>
|
||||
<form action="<?= base_url('login') ?>" method="POST" class="space-y-4">
|
||||
<?= csrf_field() ?>
|
||||
<div>
|
||||
<label class="block text-sm font-bold text-gray-700 mb-1" for="login_id">아이디</label>
|
||||
<input class="block w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:ring-2 focus:ring-[#007bff]/40 focus:border-[#007bff]" id="login_id" name="login_id" type="text" placeholder="아이디" value="<?= esc(old('login_id')) ?>" autocomplete="username" autofocus/>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-bold text-gray-700 mb-1" for="password">비밀번호</label>
|
||||
<input class="block w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:ring-2 focus:ring-[#007bff]/40 focus:border-[#007bff]" id="password" name="password" type="password" placeholder="비밀번호" autocomplete="current-password"/>
|
||||
</div>
|
||||
<div class="flex gap-2 pt-2">
|
||||
<button type="submit" class="bg-btn-search text-white px-4 py-2 rounded-lg text-sm font-semibold shadow hover:brightness-110 transition border border-transparent">로그인</button>
|
||||
<a href="<?= base_url('register') ?>" class="bg-white text-gray-700 border border-gray-300 px-4 py-2 rounded-lg text-sm shadow-sm hover:bg-gray-50 transition">회원가입</a>
|
||||
</div>
|
||||
</form>
|
||||
<?= $this->endSection() ?>
|
||||
|
||||
@@ -1,60 +1,18 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ko">
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
|
||||
<title>2차 인증 - 종량제 시스템</title>
|
||||
<script src="https://cdn.tailwindcss.com?plugins=forms,container-queries"></script>
|
||||
<style data-purpose="global-font-scale">html{font-size:18px}.app-brand,.app-brand *{font-size:16px}</style>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@300;400;500;700&display=swap" rel="stylesheet"/>
|
||||
<script>
|
||||
tailwind.config = {
|
||||
theme: {
|
||||
extend: {
|
||||
fontFamily: { sans: ['"Malgun Gothic"', '"Noto Sans KR"', 'sans-serif'] },
|
||||
colors: {
|
||||
'system-header': '#ffffff',
|
||||
'title-bar': '#2c3e50',
|
||||
'control-panel': '#f8f9fa',
|
||||
'btn-search': '#1c4e80',
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style>body { -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; }</style>
|
||||
</head>
|
||||
<body class="bg-gray-100 text-gray-800 flex flex-col min-h-screen font-sans antialiased">
|
||||
<header class="bg-white border-b border-gray-300 h-12 flex items-center justify-between px-4 shrink-0">
|
||||
<?= view('components/header_brand') ?>
|
||||
</header>
|
||||
<div class="bg-title-bar text-white px-4 py-2 text-sm font-medium shrink-0">
|
||||
2차 인증 (TOTP)
|
||||
</div>
|
||||
<?php if (session()->getFlashdata('error')): ?>
|
||||
<div class="mx-4 mt-2 p-3 rounded-lg bg-red-50 text-red-700 text-sm" role="alert"><?= esc(session()->getFlashdata('error')) ?></div>
|
||||
<?php endif; ?>
|
||||
<?php if (session()->getFlashdata('errors')): ?>
|
||||
<div class="mx-4 mt-2 p-3 rounded-lg bg-red-50 text-red-700 text-sm space-y-1" role="alert">
|
||||
<?php foreach (session()->getFlashdata('errors') as $error): ?><p><?= esc($error) ?></p><?php endforeach; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<main class="flex-grow bg-control-panel border-b border-gray-300 p-6 flex items-center justify-center">
|
||||
<section class="w-full max-w-md bg-white border border-gray-300 rounded shadow-sm p-6 space-y-4">
|
||||
<p class="text-sm text-gray-600">계정 <strong class="text-gray-800"><?= esc($memberId) ?></strong> 에 대해 인증 앱의 6자리 코드를 입력해 주세요.</p>
|
||||
<form action="<?= base_url('login/two-factor') ?>" method="POST" class="space-y-4">
|
||||
<?= csrf_field() ?>
|
||||
<div>
|
||||
<label class="block text-sm font-bold text-gray-700 mb-1" for="totp_code">인증 코드</label>
|
||||
<input class="block w-full border border-gray-300 rounded px-3 py-2 text-sm tracking-widest focus:ring-blue-500 focus:border-blue-500" id="totp_code" name="totp_code" type="text" inputmode="numeric" pattern="[0-9]*" maxlength="6" autocomplete="one-time-code" autofocus placeholder="000000" value="<?= esc(old('totp_code')) ?>"/>
|
||||
</div>
|
||||
<div class="flex gap-2 pt-2">
|
||||
<button type="submit" class="bg-btn-search text-white px-4 py-2 rounded-sm text-sm font-medium shadow hover:opacity-90 transition border border-transparent">확인</button>
|
||||
<a href="<?= base_url('login') ?>" class="bg-white text-gray-700 border border-gray-300 px-4 py-2 rounded-sm text-sm shadow hover:bg-gray-50 transition">처음으로</a>
|
||||
</div>
|
||||
</form>
|
||||
</section>
|
||||
</main>
|
||||
<footer class="bg-gray-200 border-t border-gray-300 px-4 py-1 text-xs text-gray-600 shrink-0">종량제 시스템</footer>
|
||||
</body>
|
||||
</html>
|
||||
<?= $this->extend('auth/_shell') ?>
|
||||
|
||||
<?= $this->section('heading') ?>2차 인증 (TOTP)<?= $this->endSection() ?>
|
||||
|
||||
<?= $this->section('content') ?>
|
||||
<p class="text-sm text-gray-600 mb-4">계정 <strong class="text-gray-800"><?= esc($memberId) ?></strong> 에 대해 인증 앱의 6자리 코드를 입력해 주세요.</p>
|
||||
<form action="<?= base_url('login/two-factor') ?>" method="POST" class="space-y-4">
|
||||
<?= csrf_field() ?>
|
||||
<div>
|
||||
<label class="block text-sm font-bold text-gray-700 mb-1" for="totp_code">인증 코드</label>
|
||||
<input class="block w-full border border-gray-300 rounded-lg px-3 py-2 text-sm tracking-widest focus:ring-2 focus:ring-[#007bff]/40 focus:border-[#007bff]" id="totp_code" name="totp_code" type="text" inputmode="numeric" pattern="[0-9]*" maxlength="6" autocomplete="one-time-code" autofocus placeholder="000000" value="<?= esc(old('totp_code')) ?>"/>
|
||||
</div>
|
||||
<div class="flex gap-2 pt-2">
|
||||
<button type="submit" class="bg-btn-search text-white px-4 py-2 rounded-lg text-sm font-semibold shadow hover:brightness-110 transition border border-transparent">확인</button>
|
||||
<a href="<?= base_url('login') ?>" class="bg-white text-gray-700 border border-gray-300 px-4 py-2 rounded-lg text-sm shadow-sm hover:bg-gray-50 transition">처음으로</a>
|
||||
</div>
|
||||
</form>
|
||||
<?= $this->endSection() ?>
|
||||
|
||||
@@ -1,101 +1,59 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ko">
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
|
||||
<title>회원가입 - 종량제 시스템</title>
|
||||
<script src="https://cdn.tailwindcss.com?plugins=forms,container-queries"></script>
|
||||
<style data-purpose="global-font-scale">html{font-size:18px}.app-brand,.app-brand *{font-size:16px}</style>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@300;400;500;700&display=swap" rel="stylesheet"/>
|
||||
<script>
|
||||
tailwind.config = {
|
||||
theme: {
|
||||
extend: {
|
||||
fontFamily: { sans: ['"Malgun Gothic"', '"Noto Sans KR"', 'sans-serif'] },
|
||||
colors: {
|
||||
'system-header': '#ffffff',
|
||||
'title-bar': '#2c3e50',
|
||||
'control-panel': '#f8f9fa',
|
||||
'btn-search': '#1c4e80',
|
||||
'btn-exit': '#d9534f',
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style>body { -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; }</style>
|
||||
</head>
|
||||
<body class="bg-gray-100 text-gray-800 flex flex-col h-screen font-sans antialiased">
|
||||
<header class="bg-white border-b border-gray-300 h-12 flex items-center justify-between px-4 shrink-0">
|
||||
<?= view('components/header_brand') ?>
|
||||
</header>
|
||||
<div class="bg-title-bar text-white px-4 py-2 text-sm font-medium shrink-0">
|
||||
회원가입
|
||||
</div>
|
||||
<?php if (session()->getFlashdata('error')): ?>
|
||||
<div class="mx-4 mt-2 p-3 rounded-lg bg-red-50 text-red-700 text-sm" role="alert"><?= esc(session()->getFlashdata('error')) ?></div>
|
||||
<?php endif; ?>
|
||||
<?php if (session()->getFlashdata('errors')): ?>
|
||||
<div class="mx-4 mt-2 p-3 rounded-lg bg-red-50 text-red-700 text-sm space-y-1" role="alert">
|
||||
<?php foreach (session()->getFlashdata('errors') as $error): ?><p><?= esc($error) ?></p><?php endforeach; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<main class="flex-grow bg-control-panel border-b border-gray-300 p-6 overflow-auto">
|
||||
<section class="w-full max-w-md mx-auto bg-white border border-gray-300 rounded shadow-sm p-6">
|
||||
<form action="<?= base_url('register') ?>" method="POST" class="space-y-4">
|
||||
<?= csrf_field() ?>
|
||||
<div>
|
||||
<label class="block text-sm font-bold text-gray-700 mb-1" for="mb_id">아이디 <span class="text-red-500">*</span></label>
|
||||
<input class="block w-full border border-gray-300 rounded px-3 py-2 text-sm focus:ring-blue-500 focus:border-blue-500" id="mb_id" name="mb_id" type="text" value="<?= esc(old('mb_id')) ?>" autocomplete="username" autofocus/>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-bold text-gray-700 mb-1" for="mb_passwd">비밀번호 <span class="text-red-500">*</span></label>
|
||||
<input class="block w-full border border-gray-300 rounded px-3 py-2 text-sm focus:ring-blue-500 focus:border-blue-500" id="mb_passwd" name="mb_passwd" type="password" autocomplete="new-password"/>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-bold text-gray-700 mb-1" for="mb_passwd_confirm">비밀번호 확인 <span class="text-red-500">*</span></label>
|
||||
<input class="block w-full border border-gray-300 rounded px-3 py-2 text-sm focus:ring-blue-500 focus:border-blue-500" id="mb_passwd_confirm" name="mb_passwd_confirm" type="password" autocomplete="new-password"/>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-bold text-gray-700 mb-1" for="mb_name">이름 <span class="text-red-500">*</span></label>
|
||||
<input class="block w-full border border-gray-300 rounded px-3 py-2 text-sm focus:ring-blue-500 focus:border-blue-500" id="mb_name" name="mb_name" type="text" value="<?= esc(old('mb_name')) ?>" autocomplete="name"/>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-bold text-gray-700 mb-1" for="mb_email">이메일</label>
|
||||
<input class="block w-full border border-gray-300 rounded px-3 py-2 text-sm focus:ring-blue-500 focus:border-blue-500" id="mb_email" name="mb_email" type="email" value="<?= esc(old('mb_email')) ?>"/>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-bold text-gray-700 mb-1" for="mb_phone">연락처</label>
|
||||
<input class="block w-full border border-gray-300 rounded px-3 py-2 text-sm focus:ring-blue-500 focus:border-blue-500" id="mb_phone" name="mb_phone" type="tel" value="<?= esc(old('mb_phone')) ?>"/>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-bold text-gray-700 mb-1" for="mb_lg_idx">지자체</label>
|
||||
<select class="block w-full border border-gray-300 rounded px-3 py-2 text-sm focus:ring-blue-500 focus:border-blue-500" id="mb_lg_idx" name="mb_lg_idx">
|
||||
<option value="">선택 안 함</option>
|
||||
<?php if (! empty($localGovernments)): ?>
|
||||
<?php foreach ($localGovernments as $lg): ?>
|
||||
<option value="<?= $lg->lg_idx ?>" <?= (string) old('mb_lg_idx') === (string) $lg->lg_idx ? 'selected' : '' ?>><?= esc($lg->lg_name) ?></option>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-bold text-gray-700 mb-1" for="mb_level">사용자 역할 <span class="text-red-500">*</span></label>
|
||||
<select class="block w-full border border-gray-300 rounded px-3 py-2 text-sm focus:ring-blue-500 focus:border-blue-500" id="mb_level" name="mb_level">
|
||||
<?php foreach (config('Roles')->levelNames as $level => $name): ?>
|
||||
<?php if (\Config\Roles::isSuperAdminEquivalent((int) $level)) continue; ?>
|
||||
<option value="<?= $level ?>" <?= old('mb_level', config('Roles')->defaultLevelForSelfRegister) == $level ? 'selected' : '' ?>><?= esc($name) ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
<p class="text-xs text-gray-500 mt-1">가입 후 관리자 승인 완료 시 로그인할 수 있습니다.</p>
|
||||
</div>
|
||||
<div class="flex gap-2 pt-2">
|
||||
<button type="submit" class="bg-btn-search text-white px-4 py-2 rounded-sm text-sm font-medium shadow hover:opacity-90 transition">가입하기</button>
|
||||
<a href="<?= base_url('login') ?>" class="bg-white text-gray-700 border border-gray-300 px-4 py-2 rounded-sm text-sm shadow hover:bg-gray-50 transition">로그인</a>
|
||||
</div>
|
||||
</form>
|
||||
</section>
|
||||
</main>
|
||||
<footer class="bg-gray-200 border-t border-gray-300 px-4 py-1 text-xs text-gray-600 shrink-0">종량제 시스템</footer>
|
||||
</body>
|
||||
</html>
|
||||
<?= $this->extend('auth/_shell') ?>
|
||||
|
||||
<?= $this->section('heading') ?>회원가입<?= $this->endSection() ?>
|
||||
|
||||
<?= $this->section('content') ?>
|
||||
<?php $inputCls = 'block w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:ring-2 focus:ring-[#007bff]/40 focus:border-[#007bff]'; ?>
|
||||
<form action="<?= base_url('register') ?>" method="POST" class="space-y-4">
|
||||
<?= csrf_field() ?>
|
||||
<div>
|
||||
<label class="block text-sm font-bold text-gray-700 mb-1" for="mb_id">아이디 <span class="text-red-500">*</span></label>
|
||||
<input class="<?= $inputCls ?>" id="mb_id" name="mb_id" type="text" value="<?= esc(old('mb_id')) ?>" autocomplete="username" autofocus/>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-bold text-gray-700 mb-1" for="mb_passwd">비밀번호 <span class="text-red-500">*</span></label>
|
||||
<input class="<?= $inputCls ?>" id="mb_passwd" name="mb_passwd" type="password" autocomplete="new-password"/>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-bold text-gray-700 mb-1" for="mb_passwd_confirm">비밀번호 확인 <span class="text-red-500">*</span></label>
|
||||
<input class="<?= $inputCls ?>" id="mb_passwd_confirm" name="mb_passwd_confirm" type="password" autocomplete="new-password"/>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-bold text-gray-700 mb-1" for="mb_name">이름 <span class="text-red-500">*</span></label>
|
||||
<input class="<?= $inputCls ?>" id="mb_name" name="mb_name" type="text" value="<?= esc(old('mb_name')) ?>" autocomplete="name"/>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-bold text-gray-700 mb-1" for="mb_email">이메일</label>
|
||||
<input class="<?= $inputCls ?>" id="mb_email" name="mb_email" type="email" value="<?= esc(old('mb_email')) ?>"/>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-bold text-gray-700 mb-1" for="mb_phone">연락처</label>
|
||||
<input class="<?= $inputCls ?>" id="mb_phone" name="mb_phone" type="tel" value="<?= esc(old('mb_phone')) ?>"/>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-bold text-gray-700 mb-1" for="mb_lg_idx">지자체</label>
|
||||
<select class="<?= $inputCls ?>" id="mb_lg_idx" name="mb_lg_idx">
|
||||
<option value="">선택 안 함</option>
|
||||
<?php if (! empty($localGovernments)): ?>
|
||||
<?php foreach ($localGovernments as $lg): ?>
|
||||
<option value="<?= $lg->lg_idx ?>" <?= (string) old('mb_lg_idx') === (string) $lg->lg_idx ? 'selected' : '' ?>><?= esc($lg->lg_name) ?></option>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-bold text-gray-700 mb-1" for="mb_level">사용자 역할 <span class="text-red-500">*</span></label>
|
||||
<select class="<?= $inputCls ?>" id="mb_level" name="mb_level">
|
||||
<?php foreach (config('Roles')->levelNames as $level => $name): ?>
|
||||
<?php if (\Config\Roles::isSuperAdminEquivalent((int) $level)) continue; ?>
|
||||
<option value="<?= $level ?>" <?= old('mb_level', config('Roles')->defaultLevelForSelfRegister) == $level ? 'selected' : '' ?>><?= esc($name) ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
<p class="text-xs text-gray-500 mt-1">가입 후 관리자 승인 완료 시 로그인할 수 있습니다.</p>
|
||||
</div>
|
||||
<div class="flex gap-2 pt-2">
|
||||
<button type="submit" class="bg-btn-search text-white px-4 py-2 rounded-lg text-sm font-semibold shadow hover:brightness-110 transition">가입하기</button>
|
||||
<a href="<?= base_url('login') ?>" class="bg-white text-gray-700 border border-gray-300 px-4 py-2 rounded-lg text-sm shadow-sm hover:bg-gray-50 transition">로그인</a>
|
||||
</div>
|
||||
</form>
|
||||
<?= $this->endSection() ?>
|
||||
|
||||
@@ -1,70 +1,29 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ko">
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
|
||||
<title>2차 인증 등록 - 종량제 시스템</title>
|
||||
<script src="https://cdn.tailwindcss.com?plugins=forms,container-queries"></script>
|
||||
<style data-purpose="global-font-scale">html{font-size:18px}.app-brand,.app-brand *{font-size:16px}</style>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@300;400;500;700&display=swap" rel="stylesheet"/>
|
||||
<script>
|
||||
tailwind.config = {
|
||||
theme: {
|
||||
extend: {
|
||||
fontFamily: { sans: ['"Malgun Gothic"', '"Noto Sans KR"', 'sans-serif'] },
|
||||
colors: {
|
||||
'title-bar': '#2c3e50',
|
||||
'control-panel': '#f8f9fa',
|
||||
'btn-search': '#1c4e80',
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style>body { -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; }</style>
|
||||
</head>
|
||||
<body class="bg-gray-100 text-gray-800 flex flex-col min-h-screen font-sans antialiased">
|
||||
<header class="bg-white border-b border-gray-300 h-12 flex items-center px-4 shrink-0">
|
||||
<?= view('components/header_brand') ?>
|
||||
</header>
|
||||
<div class="bg-title-bar text-white px-4 py-2 text-sm font-medium shrink-0">
|
||||
2차 인증 앱 등록
|
||||
<?= $this->extend('auth/_shell') ?>
|
||||
|
||||
<?= $this->section('heading') ?>2차 인증 앱 등록<?= $this->endSection() ?>
|
||||
|
||||
<?= $this->section('content') ?>
|
||||
<p class="text-sm text-gray-600 mb-4">관리자 계정 <strong class="text-gray-800"><?= esc($memberId) ?></strong> 에 Google Authenticator, Microsoft Authenticator 등으로 아래 시크릿 또는 QR을 등록한 뒤, 표시되는 6자리 코드를 입력해 주세요.</p>
|
||||
<?php if (! empty($qrDataUri)): ?>
|
||||
<div class="flex justify-center mb-4">
|
||||
<img src="<?= esc($qrDataUri, 'attr') ?>" alt="TOTP QR 코드" class="border border-gray-200 rounded-lg max-w-[200px] h-auto"/>
|
||||
</div>
|
||||
<?php if (session()->getFlashdata('error')): ?>
|
||||
<div class="mx-4 mt-2 p-3 rounded-lg bg-red-50 text-red-700 text-sm" role="alert"><?= esc(session()->getFlashdata('error')) ?></div>
|
||||
<?php else: ?>
|
||||
<p class="text-xs text-amber-700 bg-amber-50 border border-amber-200 rounded p-2 mb-4">QR 이미지를 불러올 수 없습니다. 아래 시크릿을 앱에 직접 입력해 주세요.</p>
|
||||
<?php endif; ?>
|
||||
<?php if (session()->getFlashdata('errors')): ?>
|
||||
<div class="mx-4 mt-2 p-3 rounded-lg bg-red-50 text-red-700 text-sm space-y-1" role="alert">
|
||||
<?php foreach (session()->getFlashdata('errors') as $error): ?><p><?= esc($error) ?></p><?php endforeach; ?>
|
||||
<div class="mb-4">
|
||||
<span class="block text-xs font-semibold text-gray-500 mb-1">수동 입력용 시크릿</span>
|
||||
<code class="block text-sm bg-gray-100 border border-gray-200 rounded-lg px-3 py-2 break-all select-all"><?= esc($secret) ?></code>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<main class="flex-grow bg-control-panel border-b border-gray-300 p-6 flex items-center justify-center">
|
||||
<section class="w-full max-w-lg bg-white border border-gray-300 rounded shadow-sm p-6 space-y-4">
|
||||
<p class="text-sm text-gray-600">관리자 계정 <strong class="text-gray-800"><?= esc($memberId) ?></strong> 에 Google Authenticator, Microsoft Authenticator 등으로 아래 시크릿 또는 QR을 등록한 뒤, 표시되는 6자리 코드를 입력해 주세요.</p>
|
||||
<?php if (! empty($qrDataUri)): ?>
|
||||
<div class="flex justify-center">
|
||||
<img src="<?= esc($qrDataUri, 'attr') ?>" alt="TOTP QR 코드" class="border border-gray-200 rounded max-w-[200px] h-auto"/>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<p class="text-xs text-amber-700 bg-amber-50 border border-amber-200 rounded p-2">QR 이미지를 불러올 수 없습니다. 아래 시크릿을 앱에 직접 입력해 주세요.</p>
|
||||
<?php endif; ?>
|
||||
<div>
|
||||
<span class="block text-xs font-semibold text-gray-500 mb-1">수동 입력용 시크릿</span>
|
||||
<code class="block text-sm bg-gray-100 border border-gray-200 rounded px-3 py-2 break-all select-all"><?= esc($secret) ?></code>
|
||||
</div>
|
||||
<form action="<?= base_url('login/totp-setup') ?>" method="POST" class="space-y-4 pt-2 border-t border-gray-200">
|
||||
<?= csrf_field() ?>
|
||||
<div>
|
||||
<label class="block text-sm font-bold text-gray-700 mb-1" for="totp_code">확인용 인증 코드</label>
|
||||
<input class="block w-full border border-gray-300 rounded px-3 py-2 text-sm tracking-widest focus:ring-blue-500 focus:border-blue-500" id="totp_code" name="totp_code" type="text" inputmode="numeric" pattern="[0-9]*" maxlength="6" autocomplete="one-time-code" autofocus placeholder="000000" value="<?= esc(old('totp_code')) ?>"/>
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<button type="submit" class="bg-btn-search text-white px-4 py-2 rounded-sm text-sm font-medium shadow hover:opacity-90 transition border border-transparent">등록 완료</button>
|
||||
<a href="<?= base_url('login') ?>" class="bg-white text-gray-700 border border-gray-300 px-4 py-2 rounded-sm text-sm shadow hover:bg-gray-50 transition">취소</a>
|
||||
</div>
|
||||
</form>
|
||||
</section>
|
||||
</main>
|
||||
<footer class="bg-gray-200 border-t border-gray-300 px-4 py-1 text-xs text-gray-600 shrink-0">종량제 시스템</footer>
|
||||
</body>
|
||||
</html>
|
||||
<form action="<?= base_url('login/totp-setup') ?>" method="POST" class="space-y-4 pt-2 border-t border-gray-200">
|
||||
<?= csrf_field() ?>
|
||||
<div>
|
||||
<label class="block text-sm font-bold text-gray-700 mb-1" for="totp_code">확인용 인증 코드</label>
|
||||
<input class="block w-full border border-gray-300 rounded-lg px-3 py-2 text-sm tracking-widest focus:ring-2 focus:ring-[#007bff]/40 focus:border-[#007bff]" id="totp_code" name="totp_code" type="text" inputmode="numeric" pattern="[0-9]*" maxlength="6" autocomplete="one-time-code" autofocus placeholder="000000" value="<?= esc(old('totp_code')) ?>"/>
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<button type="submit" class="bg-btn-search text-white px-4 py-2 rounded-lg text-sm font-semibold shadow hover:brightness-110 transition border border-transparent">등록 완료</button>
|
||||
<a href="<?= base_url('login') ?>" class="bg-white text-gray-700 border border-gray-300 px-4 py-2 rounded-lg text-sm shadow-sm hover:bg-gray-50 transition">취소</a>
|
||||
</div>
|
||||
</form>
|
||||
<?= $this->endSection() ?>
|
||||
|
||||
Reference in New Issue
Block a user