535 lines
17 KiB
HTML
535 lines
17 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="ko">
|
|
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<%--<title>일반 관리자</title>--%>
|
|
|
|
<!-- CSS -->
|
|
<link rel="stylesheet" href="/mngr/css/style.css">
|
|
|
|
<!-- jquery -->
|
|
<script src="/mngr/vendor/jquery-3.7.1.min.js"></script>
|
|
|
|
<!-- JS -->
|
|
<script src="/mngr/js/script.js" defer></script>
|
|
|
|
<!-- Nice Select -->
|
|
<link rel="stylesheet" href="/mngr/vendor/jquery-nice-select/nice-select.css">
|
|
<script src="/mngr/vendor/jquery-nice-select/jquery.nice-select.min.js"></script>
|
|
|
|
<!-- Date Picker -->
|
|
<link rel="stylesheet" href="/mngr/vendor/jquery-ui/jquery-ui.min.css">
|
|
<link rel="stylesheet" href="/mngr/vendor/jquery-ui/jquery-ui.structure.css">
|
|
<script src="/mngr/vendor/jquery-ui/jquery-ui.min.js"></script>
|
|
|
|
|
|
<!-- 제이쿼리 모달 -->
|
|
<script src="/mngr/vendor/jquery-modal/jquery.modal.min.js"></script>
|
|
<link rel="stylesheet" href="/mngr/vendor/jquery-modal/jquery.modal.min.css">
|
|
|
|
<!--파비콘-->
|
|
<link rel="icon" href="/mngr/images/gcone.ico">
|
|
</head>
|
|
|
|
<body>
|
|
<div class="login__page">
|
|
<div class="login__box">
|
|
<div class="login">
|
|
<h2 class="login__pageTitle">
|
|
<div class="login__logoWrapper">
|
|
<a href="">
|
|
<img class="login__logo active" src="/mngr/images/logo_default.png" alt="gcone">
|
|
<img class="login__logo" th:each="site : ${siteList}" th:data-brand="${site.sopmalCd}"
|
|
th:src="@{${cdnurl}+${site.topFilCours}+'/'+${site.topSysFilNm}}" th:alt="${site.sopmalNm}">
|
|
</a>
|
|
<div class="header__siteSelectArrow"><span class="visually-hidden">사이트 선택</span></div>
|
|
<div class="siteSelect">
|
|
<ul class="siteSelect__list" style="width: 300%">
|
|
<li th:each="site : ${siteList}">
|
|
<button class="siteSelect__btn" th:id="${site.sopmalCd}" th:text="${site.sopmalNm}"></button>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
<span class="login__pageTitle__text">관리자</span>
|
|
</h2>
|
|
<form id="loginForm">
|
|
<div class="login__inputBox">
|
|
<input type="hidden" id="realm" th:value="${realm}">
|
|
<input type="hidden" id="redirectUri" th:value="${redirectUri}">
|
|
<input type="hidden" id="accessUrl" th:value="${accessUrl}">
|
|
<input type="hidden" id="sopMalCd" th:value="${sopMalCd}">
|
|
<input type="hidden" id="authSopmalCd" value="">
|
|
<input autofocus class="input-text full" name="username" id="username" type="text" title="아이디" placeholder="아이디"
|
|
oninput="fn_hide_alertTxt('username','mbrIdAlertText');">
|
|
<p class="login__inputBox__alertText" id="mbrIdAlertText">아이디를 입력해 주세요.</p>
|
|
<input class="input-text full" name="password" id="password" type="password" title="패스워드"
|
|
placeholder="비밀번호" onkeyup="fn_hide_alertTxt('password','mbrPwAlertText',event);">
|
|
<p class="login__inputBox__alertText" id="mbrPwAlertText">비밀번호를 입력해 주세요.</p>
|
|
</div>
|
|
<div class="login__misc">
|
|
<div class="b-checkbox-container">
|
|
<label class="b-checkbox checkbox">
|
|
<input type="checkbox" value="">
|
|
<span class="check"></span>
|
|
<span class="control-label">아이디 저장</span>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
<button class="btn full dark login__loginBtn">로그인</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</body>
|
|
|
|
<!-- 핸드폰 인증(입력) 모달 -->
|
|
<div id="phone-auth-02" class="modal" style="max-width: 480px;">
|
|
<div class="modal-header">
|
|
<h4>핸드폰 인증</h4>
|
|
</div>
|
|
<div class="modal-content" style="height: 220px;">
|
|
<input type="hidden" id="sndngInnb">
|
|
<div class="phoneAuth">
|
|
<p class="phoneAuth__text">인증번호가 전송되었습니다.</p>
|
|
<div class="phoneAuth__inputBox input-container gap-4">
|
|
<input type="text" class="input-text text-left" id="mbtlCert" title="인증번호" placeholder="인증번호 입력" maxlength="6">
|
|
<button class="btn sm primary" onclick="fn_confim_own()">확인</button>
|
|
</div>
|
|
<div class="phoneAuthTimer">
|
|
<div class="phoneAuthTimer__left">
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none">
|
|
<path
|
|
d="M12 0C5.38125 0 0 5.38125 0 12C0 18.6187 5.38125 24 12 24C18.6187 24 24 18.6187 24 12C24 5.38125 18.6187 0 12 0ZM17.4422 13.6547H11.7656C11.7563 13.6547 11.7422 13.6547 11.7328 13.6547C11.7234 13.6547 11.7094 13.6547 11.7 13.6547C11.1422 13.6547 10.6875 13.2 10.6875 12.6422V4.39219C10.6875 3.83437 11.1422 3.37969 11.7 3.37969C12.2578 3.37969 12.7125 3.83437 12.7125 4.39219V11.625H17.4469C18.0047 11.625 18.4594 12.0797 18.4594 12.6375C18.4594 13.1953 18 13.6547 17.4422 13.6547Z"
|
|
fill="#D4D4D4" />
|
|
</svg>
|
|
<span class="phoneAuthTimer__title">남은시간</span>
|
|
<span class="phoneAuthTimer__time" id="timer">03:00</span>
|
|
</div>
|
|
<button class="phoneAuthTimer__resend" onclick="$('.close-modal').click(); login_second(); event.preventDefault();">재전송</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
$(document).ready(function () {
|
|
$('.login__logo').click(function () {
|
|
$('.login__logo').removeClass('active');
|
|
$(this).addClass('active');
|
|
});
|
|
|
|
$('.header__siteSelectArrow').click(function () {
|
|
$('.siteSelect').toggleClass('active');
|
|
});
|
|
|
|
$('.siteSelect__btn').click(function () {
|
|
$('.siteSelect').removeClass('active');
|
|
$('.login__logo').removeClass('active');
|
|
let brand = $(this).attr('id');
|
|
$('.login__logo[data-brand="' + brand + '"]').addClass('active');
|
|
$('#authSopmalCd').val(brand); // 기본값을 제공
|
|
});
|
|
|
|
//아이디 저장시 alert메시지 삭제
|
|
fn_hide_alertTxt('username','mbrIdAlertText');
|
|
});
|
|
|
|
/* ********************************************************
|
|
* 체크박스 값변경
|
|
******************************************************** */
|
|
const fn_set_checkbox = function(_target) {
|
|
|
|
if ($(_target).is(':checked')) {
|
|
|
|
$(_target).val('Y');
|
|
} else {
|
|
|
|
$(_target).val('N');
|
|
}
|
|
}
|
|
|
|
/* ********************************************************
|
|
* 아이디 저장 기능 구현
|
|
******************************************************** */
|
|
document.addEventListener('DOMContentLoaded', function () {
|
|
const usernameInput = document.getElementById('username');
|
|
const rememberCheckbox = document.querySelector('input[type="checkbox"]');
|
|
const savedUsername = localStorage.getItem('savedUsername');
|
|
|
|
// 페이지 로드 시, 저장된 아이디가 있으면 입력 필드에 채워넣기
|
|
if (savedUsername) {
|
|
usernameInput.value = savedUsername;
|
|
rememberCheckbox.checked = true; // 체크박스도 체크 상태로 유지
|
|
}
|
|
|
|
// 체크박스 상태 변경 시 아이디 저장 또는 삭제
|
|
rememberCheckbox.addEventListener('change', function () {
|
|
if (this.checked) {
|
|
// 체크된 경우, 아이디를 localStorage에 저장
|
|
const username = usernameInput.value;
|
|
if (username) {
|
|
localStorage.setItem('savedUsername', username);
|
|
}
|
|
} else {
|
|
// 체크 해제된 경우, 저장된 아이디 삭제
|
|
localStorage.removeItem('savedUsername');
|
|
}
|
|
});
|
|
});
|
|
|
|
/* ********************************************************
|
|
* 로그인(2차인증)
|
|
******************************************************** */
|
|
document.getElementById('loginForm').addEventListener('submit', function(e) {
|
|
e.preventDefault();
|
|
login_second();
|
|
});
|
|
|
|
function login_second(e) {
|
|
|
|
const username = document.getElementById('username').value.replace(/\s+/g, '');
|
|
const password = document.getElementById('password').value.replace(/\s+/g, '');
|
|
const accessUrl = document.getElementById('accessUrl').value;
|
|
|
|
//1. GC_MANAGER 테이블 제한IP, 핸드폰 인증 여부 확인
|
|
fetch(`/login/loginCheck`, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify({
|
|
username: username,
|
|
password: password,
|
|
accessUrl: accessUrl
|
|
})
|
|
})
|
|
.then(response => {
|
|
console.log(response)
|
|
if (response.ok) {
|
|
return response.json();
|
|
}else{
|
|
switch(response.status){
|
|
case 401:
|
|
throw new Error('회원아이디나 비밀번호를 다시 확인해주세요.');
|
|
case 404:
|
|
break;
|
|
default:
|
|
throw new Error('회원 로그인에 실패하였습니다. 관리자에게 문의해주세요.');
|
|
}
|
|
}
|
|
})
|
|
.then(data => {
|
|
let lmttIpAt = data.lmttIpAt;
|
|
let mblphonCrtfcAt = data.mblphonCrtfcAt;
|
|
|
|
//2. 제한IP 체크 후 로그인 처리
|
|
if(lmttIpAt == 'Y'){
|
|
//3. 핸드폰 인증여부 체크
|
|
if(mblphonCrtfcAt == 'Y'){
|
|
// 핸드폰 인증 모달 호출
|
|
$('.phoneAuth__text').text(fn_format_mbtlnb(data.mbtlnb).replace(/(\d{3})-(\d{4})-(\d{4})/, "$1-****-$3")+'로 인증번호가 전송되었습니다.');
|
|
$('#phone-auth-02').modal('show');
|
|
fn_sending_number(data.mngrNm, data.mbtlnb);
|
|
}else {
|
|
login();
|
|
}
|
|
}else {
|
|
alert('접속 가능한 IP가 아닙니다.')
|
|
}
|
|
})
|
|
.catch(error => {
|
|
console.error('Error:', error);
|
|
alert('로그인 실패: ' + error.message);
|
|
});
|
|
}
|
|
|
|
/* ********************************************************
|
|
* 로그인
|
|
******************************************************** */
|
|
function login() {
|
|
const realm = document.getElementById('realm').value;
|
|
const username = document.getElementById('username').value.replace(/\s+/g, '');
|
|
const password = document.getElementById('password').value.replace(/\s+/g, '');
|
|
var redirectUri = document.getElementById('redirectUri').value;
|
|
var accessUrl = document.getElementById('accessUrl').value;
|
|
const sopMalCd = document.getElementById('sopMalCd').value;
|
|
const authSopmalCd = document.getElementById('authSopmalCd').value;
|
|
|
|
fetch(`/login/${realm}`, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify({
|
|
username: username,
|
|
password: password,
|
|
redirectUri: redirectUri,
|
|
accessUrl: accessUrl,
|
|
sopMalCd: sopMalCd
|
|
})
|
|
})
|
|
.then(response => {
|
|
console.log(response)
|
|
if (response.ok) {
|
|
return response;
|
|
}else{
|
|
switch(response.status){
|
|
case 401:
|
|
throw new Error('회원아이디나 비밀번호를 다시 확인해주세요.');
|
|
case 404:
|
|
break;
|
|
default:
|
|
throw new Error('회원 로그인에 실패하였습니다. 관리자에게 문의해주세요.');
|
|
}
|
|
}
|
|
})
|
|
.then(data => {
|
|
console.log('Login successful', data);
|
|
let moveTo = redirectUri;
|
|
// 로그아웃 상태에서 redirectUri 가 crm 인경우 안먹는 문제 해결
|
|
const firstPath = moveTo.split('/')[3]; // "/"를 기준으로 분리
|
|
if (firstPath === 'crm') {
|
|
console.log('CRM 페이지로 리다이렉션 처리');
|
|
if(redirectUri === '') moveTo = '/mngr/main?authSopmalCd=\'+authSopmalCd'
|
|
const encodedRedirectURL = encodeURIComponent(moveTo);
|
|
window.location.href = '/sso/'+realm+'?redirectUrl='+encodedRedirectURL;
|
|
}else{
|
|
if(authSopmalCd !== '') {
|
|
|
|
if(moveTo.endsWith("/mngr")){
|
|
moveTo = redirectUri +'/main?authSopmalCd='+authSopmalCd;
|
|
}else{
|
|
moveTo = redirectUri +'/mngr/main?authSopmalCd='+authSopmalCd;
|
|
}
|
|
}
|
|
const encodedRedirectURL = encodeURIComponent(moveTo);
|
|
window.location.href = '/sso/'+realm+'?redirectUrl='+encodedRedirectURL;
|
|
}
|
|
})
|
|
.catch(error => {
|
|
console.error('Error:', error);
|
|
alert('로그인 실패: ' + error.message);
|
|
});
|
|
}
|
|
|
|
//로그인 input 이벤트
|
|
function fn_hide_alertTxt(targetId, targetAlertId,event) {
|
|
const inputLen = document.querySelector("#" + targetId).value.length;
|
|
const target = document.querySelector("#"+targetId);
|
|
const targetAlert = document.querySelector("#"+targetAlertId);
|
|
let message;
|
|
if(targetId === 'username'){
|
|
message = '아이디를 입력해 주세요.';
|
|
}else{
|
|
if(inputLen > 0){
|
|
if (event.getModifierState("CapsLock")) {
|
|
message = 'Caps Lock이 켜져 있습니다.';
|
|
}else{
|
|
message = '';
|
|
}
|
|
}else{
|
|
message = '비밀번호를 입력해 주세요.';
|
|
}
|
|
}
|
|
const targetHtml = `<p class="login__inputBox__alertText" id = "${targetAlertId}">${message}</p>`;
|
|
if (targetAlert) {
|
|
targetAlert.remove();
|
|
}
|
|
if(inputLen > 0){
|
|
if (targetId === 'password') {
|
|
target.insertAdjacentHTML('afterend', targetHtml);
|
|
}
|
|
}else{
|
|
target.insertAdjacentHTML('afterend', targetHtml);
|
|
}
|
|
}
|
|
|
|
/* ********************************************************
|
|
* 휴대폰 포매팅
|
|
******************************************************** */
|
|
const fn_format_mbtlnb = (mbtlnb) => {
|
|
if(mbtlnb != '' || mbtlnb !== undefined){
|
|
if (mbtlnb.length <= 11) {
|
|
if (mbtlnb.length == 11) {
|
|
//휴대전호번호 혹은 02를 제외한 전화번호
|
|
mbtlnb = mbtlnb.replace(/(\d{3})(\d{4})(\d{4})/, '$1-$2-$3');
|
|
} else if (mbtlnb.length == 9) {
|
|
//02를 포함한 9자리 전화번호(02-000-0000)
|
|
mbtlnb = mbtlnb.replace(/(\d{2})(\d{3})(\d{4})/, '$1-$2-$3');
|
|
} else if (mbtlnb.length == 8) {
|
|
//대표전화번호 일경우(0000-0000)
|
|
mbtlnb = mbtlnb.replace(/(\d{4})(\d{4})/, '$1-$2');
|
|
} else {
|
|
if (mbtlnb.indexOf('02') == 0) {
|
|
//02를 포함한 10자리 전화번호(02-0000-0000)
|
|
mbtlnb = mbtlnb.replace(/(\d{2})(\d{4})(\d{4})/, '$1-$2-$3');
|
|
} else {
|
|
//02를 제외한 10자리 전화번호(032-000-0000)
|
|
mbtlnb = mbtlnb.replace(/(\d{3})(\d{3})(\d{4})/, '$1-$2-$3');
|
|
}
|
|
}
|
|
}
|
|
}else{
|
|
mbtlnb = '';
|
|
}
|
|
return mbtlnb;
|
|
}
|
|
|
|
/* ********************************************************
|
|
* 휴대폰 인증 번호 발송
|
|
******************************************************** */
|
|
first = 0;
|
|
mbtlCert = '';
|
|
const fn_sending_number = function(mngrNm, mbtlnb) {
|
|
const accessUrl = document.getElementById('accessUrl').value;
|
|
|
|
if(timerRunning){
|
|
return;
|
|
}
|
|
|
|
if(mbtlCert === mbtlnb){
|
|
first++;
|
|
}else{
|
|
first = 0;
|
|
}
|
|
|
|
mbtlCert = mbtlnb;
|
|
mbtlnb = mbtlnb.trim().replace(/-/g, '');
|
|
// /* 인증번호 임시 */
|
|
let authSopmalCd = 'IS';
|
|
|
|
fetch(`/login/insertPhoneAuth`, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify({
|
|
sopMalCd: authSopmalCd,
|
|
username: mngrNm,
|
|
mbtlnb: mbtlnb,
|
|
accessUrl: accessUrl
|
|
})
|
|
})
|
|
.then(response => {
|
|
if (!response.ok) {
|
|
throw new Error('Network response was not ok');
|
|
}
|
|
return response.json(); // JSON으로 응답을 파싱
|
|
})
|
|
.then(data => {
|
|
if(data.result == "success"){
|
|
if (first > 0) {
|
|
alert('인증번호가 재발송되었습니다.');
|
|
} else if (first === 0) {
|
|
alert('인증번호가 발송되었습니다.');
|
|
first++;
|
|
} else {
|
|
return;
|
|
}
|
|
$('#sndngInnb').val(data.sndngInnb);
|
|
}else {
|
|
alert('인증번호 발송에 실패했습니다.');
|
|
$(".close-modal").click();
|
|
return;
|
|
}
|
|
});
|
|
|
|
clearInterval(countdown);
|
|
seconds = 180;
|
|
|
|
fn_set_timeOut();
|
|
countdown = setInterval(fn_set_timeOut, 1000);
|
|
timerRunning = true;
|
|
}
|
|
|
|
/* ********************************************************
|
|
* 휴대폰 인증 카운터
|
|
******************************************************** */
|
|
let seconds;
|
|
let countdown;
|
|
let timerRunning = false;
|
|
const fn_set_timeOut = function() {
|
|
|
|
if (seconds >= 0) {
|
|
|
|
const minutes = Math.floor(seconds / 60).toString().padStart(2, '0');
|
|
const remainingSeconds = (seconds % 60).toString().padStart(2, '0');
|
|
|
|
$('#timer').text(minutes+":"+remainingSeconds);
|
|
|
|
seconds--;
|
|
} else {
|
|
|
|
$(".close-modal").click();
|
|
alert('인증번호 유효시간이 만료되었습니다.');
|
|
}
|
|
}
|
|
|
|
/* ********************************************************
|
|
* 타이머 정지 함수
|
|
******************************************************** */
|
|
const fn_stop_timer = function() {
|
|
|
|
if (timerRunning) {
|
|
clearInterval(countdown);
|
|
$('#timer').text('03:00');
|
|
$('#mbtlCert').val('');
|
|
$('#phone-auth-02').hide();
|
|
timerRunning = false;
|
|
}
|
|
}
|
|
|
|
/* ********************************************************
|
|
* 휴대폰 인증 확인
|
|
******************************************************** */
|
|
isChkd_own = false;
|
|
const fn_confim_own = function() {
|
|
|
|
if (first <= 0) return;
|
|
|
|
let sndngInnb = $('#sndngInnb').val();
|
|
let mbtlnb = mbtlCert.trim().replace(/-/g, '');
|
|
let crtnb = $('#mbtlCert').val();
|
|
let accessUrl = document.getElementById('accessUrl').value;
|
|
fn_stop_timer();
|
|
|
|
// /* 인증번호 임시 */
|
|
fetch(`/login/selectPhoneAuth`, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify({
|
|
sndngInnb: sndngInnb,
|
|
mbtlnb: mbtlnb,
|
|
crtnb: crtnb,
|
|
accessUrl: accessUrl
|
|
})
|
|
})
|
|
.then(response => {
|
|
if (!response.ok) {
|
|
throw new Error('Network response was not ok');
|
|
}
|
|
return response.json(); // JSON으로 응답을 파싱
|
|
})
|
|
.then(data => {
|
|
if(data.result == "success"){
|
|
alert('인증되었습니다.');
|
|
isChkd_own = true;
|
|
login();
|
|
}else {
|
|
alert('인증번호가 일치하지 않습니다.');
|
|
$(".close-modal").click();
|
|
return;
|
|
}
|
|
})
|
|
}
|
|
|
|
$(document).on("click", ".close-modal", function() {
|
|
fn_stop_timer();
|
|
});
|
|
</script>
|
|
</html> |