Просмотр исходного кода

Merge remote-tracking branch 'origin/order' into xodud1202

xodud1202 5 лет назад
Родитель
Сommit
761e76db71
33 измененных файлов с 2324 добавлено и 821 удалено
  1. 8 1
      pom.xml
  2. 1 0
      src/main/java/com/style24/front/biz/dao/TsfCustomerDao.java
  3. 8 0
      src/main/java/com/style24/front/biz/dao/TsfLoginDao.java
  4. 47 0
      src/main/java/com/style24/front/biz/service/TsfCustomerService.java
  5. 20 6
      src/main/java/com/style24/front/biz/service/TsfLoginService.java
  6. 257 39
      src/main/java/com/style24/front/biz/thirdparty/NiceCertify.java
  7. 309 8
      src/main/java/com/style24/front/biz/web/TsfCustomerController.java
  8. 55 3
      src/main/java/com/style24/front/biz/web/TsfMypageController.java
  9. 3 0
      src/main/java/com/style24/front/support/env/TsfConstants.java
  10. 2 18
      src/main/java/com/style24/front/support/security/TsfAuthenticationProvider.java
  11. 10 7
      src/main/java/com/style24/front/support/security/handler/TsfLoginFailureHandler.java
  12. 2 5
      src/main/java/com/style24/front/support/security/handler/TsfLoginSuccessHandler.java
  13. 2 5
      src/main/java/com/style24/front/support/security/handler/TsfRememberMeSuccessHandler.java
  14. 1 0
      src/main/java/com/style24/persistence/domain/Login.java
  15. 6 2
      src/main/java/com/style24/persistence/mybatis/shop/TsfCustomer.xml
  16. 26 12
      src/main/java/com/style24/persistence/mybatis/shop/TsfLogin.xml
  17. 12 6
      src/main/resources/config/application-locd.yml
  18. 4 0
      src/main/resources/config/application.yml
  19. BIN
      src/main/webapp/WEB-INF/lib/IPIN2Client.jar
  20. 54 23
      src/main/webapp/WEB-INF/views/web/SigninFormWeb.html
  21. 0 399
      src/main/webapp/WEB-INF/views/web/customer/FindIdAndPwdFormWeb.html
  22. 333 0
      src/main/webapp/WEB-INF/views/web/customer/FindIdFormWeb.html
  23. 0 96
      src/main/webapp/WEB-INF/views/web/customer/FindIdResultFormWeb.html
  24. 427 0
      src/main/webapp/WEB-INF/views/web/customer/FindPwdFormWeb.html
  25. 0 105
      src/main/webapp/WEB-INF/views/web/customer/FindPwdResultFormWeb.html
  26. 30 0
      src/main/webapp/WEB-INF/views/web/customer/NiceCallbackFormWeb.html
  27. 37 0
      src/main/webapp/WEB-INF/views/web/customer/NiceCellPhoneFormWeb.html
  28. 39 0
      src/main/webapp/WEB-INF/views/web/customer/NiceIpinFormWeb.html
  29. 335 0
      src/main/webapp/WEB-INF/views/web/mypage/MypageOrderDetailFormWeb.html
  30. 12 82
      src/main/webapp/WEB-INF/views/web/mypage/MypageOrderListFormWeb.html
  31. 219 0
      src/main/webapp/ux/customer/customer.js
  32. 1 1
      src/main/webapp/ux/plugins/gaga/gaga.validation.js
  33. 64 3
      src/main/webapp/ux/style24_link.js

+ 8 - 1
pom.xml

@@ -104,7 +104,14 @@
 			<scope>system</scope>
 			<systemPath>${basedir}/src/main/webapp/WEB-INF/lib/NiceID.jar</systemPath>
 		</dependency>
-		<!--//NICE-->
+		<dependency>
+			<groupId>com.IPIN2Client</groupId>
+			<artifactId>IPIN2Client</artifactId>
+			<version>1.0</version>
+			<scope>system</scope>
+			<systemPath>${basedir}/src/main/webapp/WEB-INF/lib/IPIN2Client.jar</systemPath>
+		</dependency>
+		<!--//NICE 본인인증-->
 		<!-- \\\ WEB-INF lib -->
 	</dependencies>
 	

+ 1 - 0
src/main/java/com/style24/front/biz/dao/TsfCustomerDao.java

@@ -11,4 +11,5 @@ import com.style24.core.support.annotation.ShopDs;
 @ShopDs
 public interface TsfCustomerDao {
 
+
 }

+ 8 - 0
src/main/java/com/style24/front/biz/dao/TsfLoginDao.java

@@ -39,6 +39,14 @@ public interface TsfLoginDao {
 	 */
 	int getLoginFailCount(Login login);
 
+	/**
+	 * 로그인실패정보 조회
+	 * @param login - 로그인 정보
+	 * @author gagamel
+	 * @since 2021. 2. 16
+	 */
+	Login getLoginFailInfo(Login login);
+
 	/**
 	 * 최종로그인일시 Update
 	 * @param custNo - 고객번호

+ 47 - 0
src/main/java/com/style24/front/biz/service/TsfCustomerService.java

@@ -1,11 +1,16 @@
 package com.style24.front.biz.service;
 
+import com.style24.core.biz.service.TscCustomerService;
+import com.style24.core.support.env.TscConstants;
+import com.style24.core.support.session.TscSession;
+import com.style24.persistence.domain.Customer;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
 import com.style24.front.biz.dao.TsfCustomerDao;
 
 import lombok.extern.slf4j.Slf4j;
+import org.springframework.transaction.annotation.Transactional;
 
 /**
  * 고객(회원) Service
@@ -20,4 +25,46 @@ public class TsfCustomerService {
 	@Autowired
 	private TsfCustomerDao customerDao;
 
+	@Autowired
+	private TscCustomerService coreCustomerService;
+
+
+	/**
+	 * 고객아이디 찾기
+	 *
+	 * @param customer - 고객정보
+	 * @return Customer
+	 * @author jsshin
+	 * @since 2021. 02. 08
+	 */
+	public Customer getCustomerFindId(Customer customer) {
+		customer.setSiteCd(TscConstants.Site.STYLE24.value());
+		customer.encryptData(); // 데이터 암호하
+		TscSession.setAttribute("maskingYn","Y");
+		return coreCustomerService.getCustomerInfo(customer);
+	}
+
+	/**
+	 * 임시비밀번호 조회
+	 * @param length - 비밀번호 자릿수
+	 * @return 임시비밀번호
+	 * @author jsshin
+	 * @since 2021. 02. 15
+	 */
+	public String getTemporaryPassword(int length) {
+		return coreCustomerService.getTemporaryPassword(length);
+	}
+
+	/**
+	 * 회원 비밀번호 수정
+	 * @param customer - 고객정보
+	 * @author jsshin
+	 * @since 2021. 02. 15
+	 */
+	@Transactional("shopTxnManager")
+	public void saveCustomerPassword(Customer customer) {
+		coreCustomerService.saveCustomerPassword(customer);
+	}
+
+
 }

+ 20 - 6
src/main/java/com/style24/front/biz/service/TsfLoginService.java

@@ -70,15 +70,15 @@ public class TsfLoginService {
 
 	/**
 	 * 로그인실패 남기기. 로그인실패여부가 "N:성공"이면 실패건수 0으로 초기화
-	 * @param custNo - 고객번호
+	 * @param custId - 고객ID(=로그인ID)
 	 * @param loginFailYn - 로그인실패여부(Y:실패, N:성공)
 	 * @author gagamel
 	 * @since 2020. 2. 3
 	 */
 	@Transactional("shopTxnManager")
-	public void createLoginFail(Integer custNo, String loginFailYn) {
+	public void createLoginFail(String custId, String loginFailYn) {
 		Login login = new Login();
-		login.setCustNo(custNo);
+		login.setCustId(custId);
 		login.setIpAddr(TsfSession.getIpAddress());
 		login.setSiteCd(TscConstants.Site.STYLE24.value());
 		login.setLoginFailYn(loginFailYn);
@@ -88,20 +88,34 @@ public class TsfLoginService {
 
 	/**
 	 * 로그인 실패건수 조회
-	 * @param custNo - 고객번호
+	 * @param custId - 고객ID(=로그인ID)
 	 * @return 로그인 실패건수
 	 * @author gagamel
 	 * @since 2020. 2. 3
 	 */
-	public int getLoginFailCount(Integer custNo) {
+	public int getLoginFailCount(String custId) {
 		Login login = new Login();
-		login.setCustNo(custNo);
+		login.setCustId(custId);
 		login.setIpAddr(TsfSession.getIpAddress());
 		login.setSiteCd(TscConstants.Site.STYLE24.value());
 
 		return loginDao.getLoginFailCount(login);
 	}
 
+	/**
+	 * 로그인실패정보 조회
+	 * @param custId - 고객ID(=로그인ID)
+	 * @author gagamel
+	 * @since 2021. 2. 16
+	 */
+	public Login getLoginFailInfo(String custId) {
+		Login login = new Login();
+		login.setCustId(custId);
+		login.setIpAddr(TsfSession.getIpAddress());
+		login.setSiteCd(TscConstants.Site.STYLE24.value());
+		return loginDao.getLoginFailInfo(login);
+	}
+
 	/**
 	 * 로그인유지토큰 생성
 	 * @param custNo - 고객번호

+ 257 - 39
src/main/java/com/style24/front/biz/thirdparty/NiceCertify.java

@@ -1,9 +1,11 @@
 package com.style24.front.biz.thirdparty;
 
+import Kisinfo.Check.IPIN2Client;
 import NiceID.Check.CPClient;
 import com.gagaframework.web.parameter.GagaMap;
 import com.gagaframework.web.util.GagaDateUtil;
 import com.gagaframework.web.util.GagaFileUtil;
+import com.style24.core.support.session.TscSession;
 import com.style24.front.support.security.session.TsfSession;
 import com.style24.persistence.domain.Customer;
 import lombok.extern.slf4j.Slf4j;
@@ -30,9 +32,14 @@ public class NiceCertify {
 	@Autowired
 	private Environment env;
 
+	public static final String PROTOCOL = "http://";
+
 	private String niceId;			// 나이스휴대폰인증ID
 	private String nicePwd;			// 나이스휴대폰인증비밀번호
 	private String niceCallback;	// 나이스휴대폰인증콜백URL
+	private String ipinId;			// 나이스아이핀인증ID
+	private String ipinPwd;			// 나이스아이핀인증비밀번호
+	private String ipinCallback;	// 나이스아이핀콜백URL
 	private String domain;
 
 	@PostConstruct
@@ -40,30 +47,36 @@ public class NiceCertify {
 		niceId = env.getProperty("certify.nice.id");
 		nicePwd = env.getProperty("certify.nice.pwd");
 		niceCallback = env.getProperty("certify.nice.callback");
+		ipinId = env.getProperty("certify.ipin.id");
+		ipinPwd = env.getProperty("certify.ipin.pwd");
+		ipinCallback = env.getProperty("certify.ipin.callback");
 		domain = env.getProperty("domain.front");
-		log.info("\n\n---- NiceCertify initialization started ----");
-		log.info("나이스휴대폰인증(ID: {}, PWD: {}, callback: {})", niceId, nicePwd, domain + niceCallback);
-		log.info("\n--- NiceCertify initialization completed ----\n");
+		log.debug("\n\n---- NiceCertify initialization started ----");
+		log.debug("나이스휴대폰인증(ID: {}, PWD: {}, callback: {})", niceId, nicePwd, domain + niceCallback);
+		log.debug("나이스아이핀인증(ID: {}, PWD: {}, callback: {})", ipinId, ipinPwd, domain + ipinCallback);
+		log.debug("\n--- NiceCertify initialization completed ----\n");
 	}
 
 	/**
-	 * 나이스 인증 처리
+	 * 휴대폰인증 요청
 	 * @return GagaMap
 	 * @author jsshin
 	 * @since 2021. 02. 05
 	 */
-	public GagaMap certify() {
+	public GagaMap certifyCellPhone() {
 		CPClient niceCheck = new CPClient();
 
 		String sRequestNo = niceCheck.getRequestNO(niceId);
 		log.info("sRequestNo: {}", sRequestNo);
+		TscSession.setAttribute("REQ_SEQ", sRequestNo);
 
-		String callback = GagaFileUtil.getConcatenationPath("https://" + TsfSession.getHttpServletRequest().getServerName(), niceCallback);
+		String callback = GagaFileUtil.getConcatenationPath(PROTOCOL + TsfSession.getHttpServletRequest().getServerName(), niceCallback);
 		log.info("niceCallback: {}", niceCallback);
 
 		String sAuthType = "M";	// 없으면 기본 선택화면, M: 휴대폰, C: 신용카드, X: 공인인증서
 		String sPopGubun = "N";	// Y: 취소버튼 있음, N: 취소버튼 없음
 		String sCustomize = "";	// 없으면 기본 웹페이지, Mobile: 모바일페이지
+		String sGender = "";	//없으면 기본 선택 값, 0 : 여자, 1 : 남자
 
 		// 입력될 plain 데이타를 만든다.
 		StringBuilder sPlainData = new StringBuilder();
@@ -74,34 +87,51 @@ public class NiceCertify {
 		sPlainData.append("7:ERR_URL").append(callback.getBytes().length).append(":").append(callback);
 		sPlainData.append("11:POPUP_GUBUN").append(sPopGubun.getBytes().length).append(":").append(sPopGubun);
 		sPlainData.append("9:CUSTOMIZE").append(sCustomize.getBytes().length).append(":").append(sCustomize);
+		sPlainData.append("6:GENDER").append(sGender.getBytes().length).append(":").append(sGender);
 		log.info("sPlainData: {}", sPlainData);
 
 		GagaMap resultMap = new GagaMap();
 
 		// 실제적인 암호화
 		int iRtn = niceCheck.fnEncode(niceId, nicePwd, sPlainData.toString());
-		resultMap.setInt("iRtn", iRtn);
 		log.info("iRtn: {}", iRtn);
-
 		if (iRtn != 0) { // 실패했으면
+			String errorMsg = "[" + iRtn + "]";
+			if ( iRtn == -1) {
+				errorMsg += "암호화 시스템 에러입니다.";
+			}
+			else if( iRtn == -2) {
+				errorMsg += "암호화 처리오류입니다.";
+			}
+			else if( iRtn == -3) {
+				errorMsg += "암호화 데이터 오류입니다.";
+			}
+			else if( iRtn == -9) {
+				errorMsg += "입력 데이터 오류입니다.";
+			}
+			else {
+				errorMsg += "알수 없는 에러 입니다.";
+			}
+			log.error("errorMsg : ===> {}" , errorMsg);
 			throw new IllegalStateException("안심본인인증을 사용할 수 없습니다.");
 		}
 
+		resultMap.setInt("iRtn", iRtn);
 		resultMap.setString("sEncData", niceCheck.getCipherData());
 
 		return resultMap;
 	}
 
 	/**
-	 * 나이스 인증 결과값
+	 * 휴대폰 인증 결과값
 	 * @param  customer - 인증정보
 	 * @return GagaMap
 	 * @author jsshin
 	 * @since 2021. 02. 05
 	 */
-	public GagaMap getCertifyResultInfo(Customer customer) {
+	public GagaMap getCertifyCellPhoneResultInfo(Customer customer) {
 		GagaMap resultMap = new GagaMap();
-		String sEncData = customer.getEncData();
+		String sEncData = requestReplace(customer.getEncData(),"encodeData");
 
 		if (StringUtils.isBlank(sEncData)) {
 			throw new IllegalStateException("안심본인인증을 사용할 수 없습니다.");
@@ -112,40 +142,57 @@ public class NiceCertify {
 		if (iRtn != 0) {
 			String errorMsg = "[" + iRtn + "]";
 			if (iRtn == -1) {
-				errorMsg = errorMsg + "암호화 시스템 에러";
+				errorMsg += "복호화 시스템 오류입니다.";
 			} else if (iRtn == -4) {
-				errorMsg = errorMsg + "입력 데이터 오류";
+				errorMsg += "복호화 처리 오류입니다.";
 			} else if (iRtn == -5) {
-				errorMsg = errorMsg + "복호화 해쉬 오류";
+				errorMsg += "복호화 해쉬 오류입니다.";
 			} else if (iRtn == -6) {
-				errorMsg = errorMsg + "복호화 데이터 오류";
+				errorMsg += "복호화 데이터 오류입니다.";
 			} else if (iRtn == -9) {
-				errorMsg = errorMsg + "입력 데이터 오류";
+				errorMsg += "입력 데이터 오류입니다.";
 			} else if (iRtn == -12) {
-				errorMsg = errorMsg + "사이트 비밀번호 오류";
+				errorMsg += "사이트 패스워드 오류입니다.";
 			} else {
-				errorMsg = errorMsg + "결과값 확인 후, NICE신용평가정보 개발 담당자에게 문의";
+				errorMsg += "결과값 확인 후, NICE신용평가정보 개발 담당자에게 문의";
 			}
-			throw new IllegalStateException(errorMsg);
+			log.error("errorMsg : ===> {}" , errorMsg);
+			throw new IllegalStateException("안심본인인증을 사용할 수 없습니다.");
 		}
-		String sPlan = niceCheck.getPlainData();
-		HashMap result = niceCheck.fnParse(sPlan);
+
+
+		String sPlainData = niceCheck.getPlainData();
+		String sCipherTime = niceCheck.getCipherDateTime();				// 복호화한 시간
+		HashMap result = niceCheck.fnParse(sPlainData);
+
 		log.info("휴대폰 인증 결과 값 : {}", result.toString());
 
 		if (result == null && result.isEmpty()) {
 			throw new IllegalStateException("응답값 무효 본인인증을 사용할 수 없습니다.");
 		}
 
-		String sAuthType = (String)result.get("AUTH_TYPE");
-		String sName = (String)result.get("NAME");
-		String sGender = (String)result.get("GENDER");	// F:여성, M:남성
-		String sBirthDate = (String)result.get("BIRTHDATE");
-		String sNationalInfo = (String)result.get("NATIONALINFO");
-		String sDi = (String)result.get("DI");
-		String sCi = (String)result.get("CI");
-		String sMobileNo = (String)result.get("MOBILE_NO");
+		String sRequestNumber = (String)result.get("REQ_SEQ");			// 요청 번호
+		String sResponseNumber = (String)result.get("RES_SEQ");			// 인증 고유번호
+		String sAuthType = (String)result.get("AUTH_TYPE");				// 인증 수단
+		String sName = (String)result.get("NAME");						// 성명
+		String sGender = (String)result.get("GENDER");					// 성별 F:여성, M:남성
+		String sBirthDate = (String)result.get("BIRTHDATE");			// 생년월일(YYYYMMDD)
+		String sNationalInfo = (String)result.get("NATIONALINFO");		// 내/외국인정보 0:내국인, 1:외국인
+		String sDi = (String)result.get("DI");							// 중복가입 확인값 (DI_64 byte)
+		String sCi = (String)result.get("CI");							// 연계정보 확인값 (CI_88 byte) 주문번호 1:1 이다.
+		String sMobileNo = (String)result.get("MOBILE_NO");				// 휴대폰번호
+		String sMobileCo = (String)result.get("MOBILE_CO");				// 통신사
+
+
+		String sRequestNo = TscSession.getAttribute("REQ_SEQ");	// 세션에 저장된 요청번호
+		if (!sRequestNo.equals(sRequestNumber)) {
+			sResponseNumber = "";
+			sAuthType = "";
+			throw new IllegalStateException("세션값 불일치 오류 입니다.");
+		}
+
 		String sAdult = "";		 // 미성년 : 0, 성인 : 1
-		String foreignerYn = ""; // 외국인여부(외국인:Y)
+		String sforeignerYn = ""; // 외국인여부(외국인:Y)
 
 		if ("0".equals(sGender)) {
 			sGender = "F";
@@ -158,24 +205,156 @@ public class NiceCertify {
 		}
 
 		if ("0".equals(sNationalInfo)) {
-			foreignerYn = "N";
+			sforeignerYn = "N";
 		} else if ("1".equals(sNationalInfo)) {
-			foreignerYn = "Y";
+			sforeignerYn = "Y";
 		}
 
-		resultMap.setString("authType", sAuthType);
-		resultMap.setString("custNm", sName);
-		resultMap.setString("sexGb", sGender);
-		resultMap.setString("birthYmd", sBirthDate);
-		resultMap.setString("foreignerYn", foreignerYn);
+		resultMap.setString("sAuthType", sAuthType);
+		resultMap.setString("sName", sName);
+		resultMap.setString("sGender", sGender);
+		resultMap.setString("sBirthDate", sBirthDate);
+		resultMap.setString("sforeignerYn", sforeignerYn);
 		resultMap.setString("sDi", sDi);
 		resultMap.setString("sCi", sCi);
-		resultMap.setString("cellPhnno", sMobileNo);
-		resultMap.setString("adult", sAdult);
+		resultMap.setString("sMobileNo", sMobileNo);
+		resultMap.setString("sMobileCo", sMobileCo);
+		resultMap.setString("sAdult", sAdult);
+
+		return resultMap;
+	}
+
+	/**
+	 * 아이핀 인증 요청
+	 * @return GagaMap
+	 * @author jsshin
+	 * @since 2021. 02. 09
+	 */
+	public GagaMap certifyIpin() {
+		IPIN2Client ipinClinet = new IPIN2Client();
+		String callback = GagaFileUtil.getConcatenationPath( PROTOCOL + TsfSession.getHttpServletRequest().getServerName(), ipinCallback);
+
+		String sCPRequestNo = ipinClinet.getRequestNO(ipinId);
+		TscSession.setAttribute("CPREQUEST", sCPRequestNo);
+
+		// 인증요청 암호화 데이터 생성
+		int iRtn = ipinClinet.fnRequest(ipinId, ipinPwd, sCPRequestNo, callback);
+
+		if (iRtn != 0) { // 실패했으면
+			String errorMsg = "[" + iRtn + "]";
+			if (iRtn == -1) {
+				errorMsg += "암호화 시스템 오류 : 귀사 서버 환경에 맞는 모듈을 이용해주십시오." +
+						"<br>오류가 지속되는 경우 iRtn 값, 서버 환경정보, 사이트코드를 기재해 문의주시기 바랍니다.";
+			} else if (iRtn == -2) {
+				errorMsg += "암호화 처리 오류 : 최신 모듈을 이용해주십시오. " +
+						"오류가 지속되는 경우 iRtn 값, 서버 환경정보, 사이트코드를 기재해 문의주시기 바랍니다.";
+			} else if (iRtn == -9) {
+				errorMsg += "입력 정보 오류 : 암호화 함수에 입력된 파라미터 값을 확인해주십시오." +
+						"<br>오류가 지속되는 경우, 함수 실행 직전 각 파라미터 값을 로그로 출력해 발송해주시기 바랍니다.";
+			} else {
+				errorMsg += "기타 오류: iRtn 값과 적용한 샘플소스를 발송해주시기 바랍니다.";
+			}
+			log.error("errorMsg : ===> {}" , errorMsg);
+			throw new IllegalStateException("안심본인인증을 사용할 수 없습니다.");
+		}
+
+		GagaMap resultMap = new GagaMap();
+		resultMap.setString("sEncData", ipinClinet.getCipherData());
+
+		return resultMap;
+	}
+
+	/**
+	 * 아이핀 인증 결과값
+	 * @param customer - 인증정보
+	 * @return GagaMap
+	 * @author jsshin
+	 * @since 2020. 7. 15
+	 */
+	public GagaMap getCertifyIpinResultInfo(Customer customer) {
+		GagaMap resultMap = new GagaMap();
+		String sEncData = requestReplace(customer.getEncData(), "encodeData");
+
+		if (StringUtils.isBlank(sEncData)) {
+			throw new IllegalStateException("안심본인인증을 사용할 수 없습니다.");
+		}
+
+		IPIN2Client ipinClinet = new IPIN2Client();
+		int iRtn = ipinClinet.fnResponse(ipinId, ipinPwd, sEncData);
+
+		if (iRtn != 1) {
+			String errorMsg = "[" + iRtn + "]";
+			if (iRtn == -1 || iRtn == -4) {
+				errorMsg +=  "복호화 시스템 오류 :<br> 귀사 서버 환경에 맞는 모듈을 이용해주십시오." +
+						"<br>오류가 지속되는 경우 iRtn 값, 서버 환경정보, 사이트코드를 기재해 문의주시기 바랍니다.";
+			} else if (iRtn == -6){
+				errorMsg +=  "복호화 처리 오류: 당사에서 이용하는 charset인 EUC-KR이 정상적으로 받아지는 확인해주십시오. " +
+						"<br>오류가 지속되는 경우, 개발 가이드의 <b>\"결과 데이터 확인 방법\"</b>을 참고해주시기 바랍니다.";
+			} else if (iRtn == -9) {
+				errorMsg +=  "입력 정보 오류: 복호화 함수에 입력된 파라미터 값을 확인해주십시오." +
+						"<br>오류가 지속되는 경우, 함수 실행 직전 각 파라미터 값을 로그로 출력해 발송해주시기 바랍니다.";
+			} else if (iRtn == -12) {
+				errorMsg += "CP 패스워드 불일치: IPIN 서비스 사이트패스워드를 확인해주시기 바랍니다.";
+			} else if (iRtn == -13) {
+				errorMsg += "CP 요청번호 불일치: 세션에 저장된 CP요청번호(sCPRequest) 값을 확인해주시기 바랍니다.";
+			} else {
+				errorMsg += "기타오류: iRtn 값 확인 후 NICE평가정보 전산 담당자에게 문의해주시기 바랍니다.";
+			}
+
+			log.error("errorMsg : ===> {}" , errorMsg);
+			throw new IllegalStateException("안심본인인증을 사용할 수 없습니다.");
+		}
+
+		String sVirtualNo = ipinClinet.getVNumber();		// 가상주민번호 (13자리이며, 숫자 또는 문자
+		String sName = ipinClinet.getName();				// 이름 (EUC-KR)
+		String sAgeCode = ipinClinet.getAgeCode();			// 연령대 코드 (개발 가이드 참조)
+		String sGenderCode = ipinClinet.getGenderCode();	// 성별 코드 (0:여성, 1: 남성)
+		String sBirthDate = ipinClinet.getBirthDate();		// 생년월일 (YYYYMMDD)
+		String sForeigner = ipinClinet.getNationalInfo();	// 내/외국인코드 (0:내국인, 1:외국인)
+		String sCPRequestNum = ipinClinet.getCPRequestNO();	// CP 요청번호
+		String sDupInfo = ipinClinet.getDupInfo();			// 중복가입확인값 (64byte, 개인식별값, DI:Duplicate Info)
+		String sConnInfo = ipinClinet.getCoInfo1();			// 연계정보 확인값 (88byte, 개인식별값, CI:Connecting Information)
+		String sCIUpdate = ipinClinet.getCIUpdate();		// CI 갱신정보 (1~: 가이드 참조)
+		String sAuthInfo = ipinClinet.getAuthInfo();		// 본인확인수단 (0~4: 가이드 참조)
+
+
+		String sCPRequestNo = TscSession.getAttribute("CPREQUEST");
+		if (!sCPRequestNo.equals(sCPRequestNum)) {
+			throw new IllegalStateException("세션값 불일치 오류 입니다.");
+		}
+
+		String sGender = "";
+		String sAdult = "N"; //미성년자
+		String sforeignerYn = "";
+
+		if (Integer.parseInt(sAgeCode) > 3) {
+			sAdult = "Y";//성인
+		}
+		if ("0".equals(sGenderCode)) {
+			sGender = "F";
+		} else if ("1".equals(sGenderCode)) {
+			sGender = "M";
+		}
+
+		if ("0".equals(sForeigner)) {
+			sforeignerYn = "N";
+		} else if ("1".equals(sForeigner)) {
+			sforeignerYn = "Y";
+		}
+
+		resultMap.setString("sVirtualNo", sVirtualNo);
+		resultMap.setString("sName", sName);
+		resultMap.setString("sGender", sGender);
+		resultMap.setString("sBirthDate", sBirthDate);
+		resultMap.setString("sforeignerYn", sforeignerYn);
+		resultMap.setString("sDupInfo", sDupInfo);
+		resultMap.setString("sConnInfo", sConnInfo);
+		resultMap.setString("sAdult", sAdult);
 
 		return resultMap;
 	}
 
+
 	/**
 	 * 성인여부
 	 * @param  birthDate
@@ -202,5 +381,44 @@ public class NiceCertify {
 		return sAdult;
 	}
 
+	public String requestReplace (String paramValue, String gubun) {
+
+		String result = "";
+
+		if (paramValue != null) {
+
+			paramValue = paramValue.replaceAll("<", "&lt;").replaceAll(">", "&gt;");
+
+			paramValue = paramValue.replaceAll("\\*", "");
+			paramValue = paramValue.replaceAll("\\?", "");
+			paramValue = paramValue.replaceAll("\\[", "");
+			paramValue = paramValue.replaceAll("\\{", "");
+			paramValue = paramValue.replaceAll("\\(", "");
+			paramValue = paramValue.replaceAll("\\)", "");
+			paramValue = paramValue.replaceAll("\\^", "");
+			paramValue = paramValue.replaceAll("\\$", "");
+			paramValue = paramValue.replaceAll("'", "");
+			paramValue = paramValue.replaceAll("@", "");
+			paramValue = paramValue.replaceAll("%", "");
+			paramValue = paramValue.replaceAll(";", "");
+			paramValue = paramValue.replaceAll(":", "");
+			paramValue = paramValue.replaceAll("-", "");
+			paramValue = paramValue.replaceAll("#", "");
+			paramValue = paramValue.replaceAll("--", "");
+			paramValue = paramValue.replaceAll("-", "");
+			paramValue = paramValue.replaceAll(",", "");
+
+			if(!"encodeData".equals(gubun)){
+				paramValue = paramValue.replaceAll("\\+", "");
+				paramValue = paramValue.replaceAll("/", "");
+				paramValue = paramValue.replaceAll("=", "");
+			}
+
+			result = paramValue;
+
+		}
+		return result;
+	}
+
 
 }

+ 309 - 8
src/main/java/com/style24/front/biz/web/TsfCustomerController.java

@@ -1,11 +1,19 @@
 package com.style24.front.biz.web;
 
+import com.gagaframework.web.parameter.GagaMap;
+import com.gagaframework.web.security.GagaPasswordEncoder;
 import com.gagaframework.web.util.GagaStringUtil;
+import com.style24.core.support.env.TscConstants;
+import com.style24.core.support.session.TscSession;
+import com.style24.front.biz.thirdparty.NiceCertify;
 import com.style24.front.support.security.session.TsfSession;
+import com.style24.persistence.domain.Customer;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Controller;
 import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
 
 import com.style24.core.support.message.TscMessageByLocale;
@@ -14,6 +22,7 @@ import com.style24.front.support.controller.TsfBaseController;
 
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseBody;
 import org.springframework.web.servlet.ModelAndView;
 
 /**
@@ -33,39 +42,251 @@ public class TsfCustomerController extends TsfBaseController {
 	@Autowired
 	private TsfCustomerService customerService;
 
+	@Autowired
+	private NiceCertify niceCertify;
+
+	@Autowired
+	private GagaPasswordEncoder passwordEncoder;
+
 	/**
-	 * 아이디 & 비밀번호 찾기 화면
+	 * 아이디 찾기 화면
 	 *
 	 * @return ModelAndView
 	 * @author jsshin
 	 * @since 2021. 02. 05
 	 */
 	@RequestMapping("/id/find/form")
-	public ModelAndView idFind() {
+	public ModelAndView idFindForm() {
 		ModelAndView mav = new ModelAndView();
 
-		mav.setViewName(super.getDeviceViewName("customer/FindIdAndPwdForm"));
+		mav.setViewName(super.getDeviceViewName("customer/FindIdForm"));
 
 		return mav;
 	}
 
 	/**
-	 * 아이디 찾기 결과 화면
+	 * 아이디 찾기 - 고객정보
+	 *
+	 * @return ModelAndView
+	 * @author jsshin
+	 * @since 2021. 02. 08
+	 */
+	@PostMapping("/id/find")
+	@ResponseBody
+	public GagaMap getIdFindCustInfo(@RequestBody Customer customer) {
+		GagaMap result = new GagaMap();
+		boolean isFind = false;
+
+		if (StringUtils.isBlank(customer.getAuthMethod())) {
+			throw new IllegalStateException("인증방법이 없습니다. <br>관리자에게 문의하시기 바랍니다.");
+		}
+
+		Customer params = new Customer();
+		// 인증방법
+		 GagaMap authInfo;
+		if (TscConstants.AuthMethod.CUSTINFO.value().equals(customer.getAuthMethod())) {
+			// 기본정보
+			params.setCustNm(customer.getCustNm());
+			params.setEmail(customer.getEmail());
+			params.setBirthYmd(customer.getBirthYmd());
+		} else if (TscConstants.AuthMethod.MOBILE.value().equals(customer.getAuthMethod())) {
+			// 핸드폰 인증
+			authInfo = niceCertify.getCertifyCellPhoneResultInfo(customer);
+			params.setCi(authInfo.getString("sCi"));
+		} else if (TscConstants.AuthMethod.IPIN.value().equals(customer.getAuthMethod())) {
+			// 아이핀
+			authInfo = niceCertify.getCertifyIpinResultInfo(customer);
+			params.setCi(authInfo.getString("sConnInfo"));
+		}
+
+		// 고객정보 찾기
+		Customer custInfo = customerService.getCustomerFindId(params);
+		if (custInfo != null) {
+			isFind = true;
+			result.setString("maskingCustId", custInfo.getMaskingCustId());
+			result.setString("joinDt", custInfo.getJoinDt());
+			result.setString("ysJoinDt", custInfo.getYsJoinDt());
+			result.setString("nvJoinDt", custInfo.getNvJoinDt());
+			result.setString("kkJoinDt", custInfo.getKkJoinDt());
+		}
+		result.setString("authMethod", customer.getAuthMethod()); // 인증방법
+		result.setBoolean("isFind", isFind);
+		return result;
+	}
+
+
+	/**
+	 * 비밀번호 찾기 화면
 	 *
-	 * @param confirmYn - 인증여부
 	 * @return ModelAndView
 	 * @author jsshin
 	 * @since 2021. 02. 05
 	 */
-	@GetMapping("/id/find/result/form")
-	public ModelAndView idFindResult(@RequestParam(required = false) String confirmYn) {
+	@GetMapping("/pwd/find/form")
+	public ModelAndView pwdFindForm() {
 		ModelAndView mav = new ModelAndView();
 
-		mav.setViewName(super.getDeviceViewName("customer/FindIdResultForm"));
+		mav.setViewName(super.getDeviceViewName("customer/FindPwdForm"));
 
 		return mav;
 	}
 
+	/**
+	 * 비밀번호 찾기 화면 - 아이디 확인
+	 *
+	 * @param customer - custId
+	 * @return GagaMap - 결과정보
+	 * @author jsshin
+	 * @since 2021. 02. 10
+	 */
+	@PostMapping("/id/check")
+	@ResponseBody
+	public GagaMap getIdCheck(@RequestBody Customer customer) {
+		GagaMap result = new GagaMap();
+		boolean isFind = false;
+
+		if(StringUtils.isBlank(customer.getCustId())) {
+			throw new IllegalStateException("확인 할 아이디가 없습니다.");
+		}
+
+		Customer custInfo = customerService.getCustomerFindId(customer);
+		if (custInfo != null) {
+			isFind = true;
+		}
+
+		result.setBoolean("isFind", isFind);
+		return result;
+	}
+
+
+	/**
+	 * 비밀번호 찾기 - 고객정보 찾기
+	 * @param customer - 고객정보
+	 * @return GagaMap
+	 * @author jsshin
+	 * @since 2021. 02. 15
+	 */
+	@PostMapping("/pwd/find/custinfo")
+	@ResponseBody
+	public GagaMap getPwdFind(@RequestBody Customer customer) {
+		GagaMap result = new GagaMap();
+		boolean isFind = false;
+
+		if (StringUtils.isBlank(customer.getAuthMethod())) {
+			throw new IllegalStateException("인증방법이 없습니다. <br>관리자에게 문의하시기 바랍니다.");
+		}
+
+		// 고객정보 찾기 - 아이디, 이름, 이메일
+		Customer custInfo = customerService.getCustomerFindId(customer);
+
+		if (custInfo != null) {
+			isFind = true;
+			result.setString("maskingEmail", custInfo.getMaskingEmail());
+		}
+
+		if (isFind) {
+			String tempPasswd = customerService.getTemporaryPassword(10);
+			log.info("tempPasswd  ====> {}", tempPasswd);
+			customer.setTempPasswdYn("Y"); // 임시비밀번호여부
+			customer.setPasswd(tempPasswd);
+			customer.setEncodedPasswd(passwordEncoder.encode(tempPasswd));
+			customer.setRegNo(custInfo.getCustNo());
+			customer.setUpdNo(custInfo.getCustNo());
+			customer.setCustNo(custInfo.getCustNo());
+
+			// 비밀번호 수정
+			customerService.saveCustomerPassword(customer);
+
+			// TODO: 2021.02.15 메일발송 서비스 붙여야함 - jsshin
+		}
+
+		result.setString("authMethod", customer.getAuthMethod()); // 인증방법
+		result.setBoolean("isFind", isFind);
+		return result;
+	}
+
+	/**
+	 * 비밀번호 찾기 - 인증(휴대폰,아이핀)
+	 * @param customer - 고객정보
+	 * @return GagaMap
+	 * @author jsshin
+	 * @since 2021. 02. 15
+	 */
+	@PostMapping("/pwd/find/certify")
+	@ResponseBody
+	public GagaMap getPwdFindCertify(@RequestBody Customer customer) {
+		GagaMap result = new GagaMap();
+		boolean isFind = false;
+
+		if (StringUtils.isBlank(customer.getAuthMethod())) {
+			throw new IllegalStateException("인증방법이 없습니다. <br>관리자에게 문의하시기 바랍니다.");
+		}
+
+		Customer params = new Customer();
+		// 인증방법
+		GagaMap authInfo;
+		if (TscConstants.AuthMethod.MOBILE.value().equals(customer.getAuthMethod())) {
+			// 핸드폰 인증
+			authInfo = niceCertify.getCertifyCellPhoneResultInfo(customer);
+			params.setCi(authInfo.getString("sCi"));
+		} else if (TscConstants.AuthMethod.IPIN.value().equals(customer.getAuthMethod())) {
+			// 아이핀
+			authInfo = niceCertify.getCertifyIpinResultInfo(customer);
+			params.setCi(authInfo.getString("sConnInfo"));
+		}
+
+		// 고객정보 찾기
+		Customer custInfo = customerService.getCustomerFindId(params);
+		if (custInfo != null) {
+			isFind = true;
+			TscSession.setAttribute("custNo", String.valueOf(custInfo.getCustNo()));
+			result.setString("custId", custInfo.getCustId());
+		}
+
+		result.setString("authMethod", customer.getAuthMethod()); // 인증방법
+		result.setBoolean("isFind", isFind);
+		return result;
+	}
+
+
+	/**
+	 * 비밀번호 변경
+	 *
+	 * @param customer - 비밀번호 정보
+	 * @return ModelAndView
+	 * @author jsshin
+	 * @since 2021. 02. 16
+	 */
+	@PostMapping("/password/reset")
+	@ResponseBody
+	public GagaMap resetPassword(@RequestBody Customer customer) {
+		GagaMap result = new GagaMap();
+		String custNo = TscSession.getAttribute("custNo");
+		boolean isSuccess = false;
+		if (StringUtils.isBlank(custNo)) {
+			throw new IllegalStateException("고객 정보가 없습니다. 다시 확인 해주세요.");
+		}
+
+		Customer params = new Customer();
+		params.setCustNo(Integer.valueOf(custNo));
+		// 고객정보 찾기
+		Customer custInfo = customerService.getCustomerFindId(params);
+		if (custInfo != null) {
+			customer.setTempPasswdYn("N"); // 임시비밀번호여부
+			customer.setEncodedPasswd(passwordEncoder.encode(customer.getPasswd()));
+			customer.setRegNo(custInfo.getCustNo());
+			customer.setUpdNo(custInfo.getCustNo());
+			customer.setCustNo(custInfo.getCustNo());
+			// 비밀번호 수정
+			customerService.saveCustomerPassword(customer);
+			isSuccess = true;
+		}
+		result.setBoolean("isSuccess", isSuccess);
+		return result;
+	}
+
+
+
 
 	/**
 	 * 비밀번호 찾기 결과 화면
@@ -98,6 +319,86 @@ public class TsfCustomerController extends TsfBaseController {
 		return mav;
 	}
 
+	/**
+	 * 휴대폰 인증 화면
+	 * @param redirectUrl - 모바일사용
+	 * @param custparams - 회원정보 수정시 사용
+	 * @return ModelAndView
+	 * @author jsshin
+	 * @since 2021. 02. 09
+	 */
+	@GetMapping("/nice/cellphone/form")
+	public ModelAndView niceCellphoneForm(@RequestParam(value = "redirectUrl", required = false) String redirectUrl
+			, @RequestParam(value = "custparams", required = false) String custparams) {
+		ModelAndView mav = new ModelAndView();
+		GagaMap result = niceCertify.certifyCellPhone();
+
+		if (TscConstants.FrontGb.MOBIEL.vale().equals(TsfSession.getFrontGb())) {
+			mav.addObject("redirectUrl", redirectUrl); // 모바일만 사용
+		}
+
+		mav.addObject("sEncData", result.getString("sEncData"));
+		mav.setViewName(super.getDeviceViewName("customer/NiceCellPhoneForm"));
+
+		return mav;
+	}
+
+	/**
+	 * 아이핀 인증 화면
+	 * @param redirectUrl - 모바일사용
+	 * @return ModelAndView
+	 * @author jsshin
+	 * @since 2021. 02. 09
+	 */
+	@GetMapping("/nice/ipin/form")
+	public ModelAndView getCertifyNiceIpin(@RequestParam(value = "redirectUrl", required = false) String redirectUrl) {
+		ModelAndView mav = new ModelAndView();
+		GagaMap result = niceCertify.certifyIpin();
+
+		if (TscConstants.FrontGb.MOBIEL.vale().equals(TsfSession.getFrontGb())) {
+			mav.addObject("redirectUrl", redirectUrl); // 모바일만 사용
+		}
+
+		mav.addObject("sEncData", result.getString("sEncData"));
+		mav.setViewName(super.getDeviceViewName("customer/NiceIpinForm"));
+		return mav;
+	}
+
+	/**
+	 * 나이스 인증 콜백
+	 * @param encodeData - 휴대폰인증에서 전달받은 인증결과 암호화 데이터 취득
+	 * @param encData - ipin_process에서 전달받은 인증결과 암호화 데이터 취득
+	 * @return ModelAndView
+	 * @author jsshin
+	 * @since 2021. 02. 09
+	 */
+	@RequestMapping("/nice/certify/callback")
+	public ModelAndView niceCertifyCallback(
+			@RequestParam(value = "EncodeData", required = false) String encodeData
+			, @RequestParam(value = "enc_data", required = false) String encData
+			, @RequestParam(value = "param_r1", required = false) String redirectUrl) {
+
+		ModelAndView mav = new ModelAndView(super.getDeviceViewName("customer/NiceCallbackForm"));
+		String sEncData = "";
+		String authMethod = "";
+		if (StringUtils.isNotBlank(encodeData)) {
+			sEncData = encodeData;
+			authMethod = TscConstants.AuthMethod.MOBILE.value();
+		}
+		if (StringUtils.isNotBlank(encData)) {
+			sEncData = encData;
+			authMethod = TscConstants.AuthMethod.IPIN.value();
+		}
+
+		if (TscConstants.FrontGb.MOBIEL.vale().equals(TsfSession.getFrontGb())) {
+			mav.addObject("redirectUrl", redirectUrl);
+		}
+
+		mav.addObject("sEncData", sEncData);
+		mav.addObject("authMethod", authMethod);
+
+		return mav;
+	}
 
 
 }

+ 55 - 3
src/main/java/com/style24/front/biz/web/TsfMypageController.java

@@ -5,6 +5,7 @@ import java.util.Collection;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Controller;
 import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.servlet.ModelAndView;
 
@@ -75,7 +76,7 @@ public class TsfMypageController extends TsfBaseController {
 	 * @since 2021. 02. 04
 	 */
 	@GetMapping({"/main/form", "/order/list/form"})
-	public ModelAndView mypageOrderList() {
+	public ModelAndView mypageOrderListForm() {
 		ModelAndView mav = new ModelAndView();
 		
 		// int custNo = TsfSession.getInfo().getCustNo();
@@ -83,7 +84,9 @@ public class TsfMypageController extends TsfBaseController {
 
 		// 고객정보 조회
 		Customer customer = new Customer();
+		customer.setSiteCd(TscConstants.Site.STYLE24.value());
 		customer.setCustNo(custNo);
+		customer.setCustStat(TscConstants.CustStat.ACTIVE.value());
 		customer = coreCustomerService.getCustomerInfo(customer);
 
 		mav.addObject("customerInfo", customer);
@@ -146,7 +149,56 @@ public class TsfMypageController extends TsfBaseController {
 
 		return mav;
 	}
-	
-	
+
+	/**
+	 * 마이페이지 주문상세 화면
+	 *
+	 * @return
+	 * @author card007
+	 * @since 2021. 02. 15
+	 */
+	@GetMapping({"/order/detail/form/{ordNo}"})
+	public ModelAndView mypageOrderDetailForm(@PathVariable(value = "ordNo") int ordNo) {
+		ModelAndView mav = new ModelAndView();
+
+		// int custNo = TsfSession.getInfo().getCustNo();
+		int custNo = 1000007;
+
+		// 고객정보 조회
+		Customer customer = new Customer();
+		customer.setSiteCd(TscConstants.Site.STYLE24.value());
+		customer.setCustNo(custNo);
+		customer.setCustStat(TscConstants.CustStat.ACTIVE.value());
+		customer = coreCustomerService.getCustomerInfo(customer);
+
+		mav.addObject("customerInfo", customer);
+
+		// 주문번호 설정
+		mav.addObject("ordNo", ordNo);
+
+		
+		Order order = new Order();
+		order.setCustNo(custNo);
+		order.setOrdNo(ordNo);
+		
+		// 주문목록 조회
+		mav.addObject("orderList", coreOrderService.getOrderListForMypage(order));
+
+		// 주문정보 조회
+		mav.addObject("orderInfo", coreOrderService.getOrderInfoList(order).iterator().next());
+
+		// 주문 금액정보 조회
+		mav.addObject("orderAmtInfo", coreOrderService.getOrderAmtForMypage(order));
+
+		// 주문 결제정보 조회
+		mav.addObject("paymentInfo", coreOrderService.getPaymentInfoForMypage(order));
+		
+		// 주문 배송지 정보 조회
+		mav.addObject("deliveryAddrInfo", coreOrderService.getOrderDeliveryAddrInfo(order));
+
+		mav.setViewName(super.getDeviceViewName("mypage/MypageOrderDetailForm"));
+
+		return mav;
+	}
 
 }

+ 3 - 0
src/main/java/com/style24/front/support/env/TsfConstants.java

@@ -19,6 +19,9 @@ public class TsfConstants {
 	public static final String REMEMBER_ME_PARAMETER = "rememberMe";
 	public static final int REMEMBER_ME_LIMIT = 60 * 60 * 24 * 7; // 7일간유효
 
+	// 로그인블락실패건수
+	public static final int LOGIN_BLOCK_FAIL_CNT = 10;
+
 //	// 카테고리구분
 //	public enum CATE_GB {
 //		BYITEM("101"), BYBRAND("102"), BYOUTLET("103");

+ 2 - 18
src/main/java/com/style24/front/support/security/TsfAuthenticationProvider.java

@@ -76,12 +76,8 @@ public class TsfAuthenticationProvider implements AuthenticationProvider {
 			throw new TsfUsernameNotFoundException(message.getMessage("LOGN_0001"));
 		}
 
-		// 로그인 실패누적건수가 5이면
-		if (loginInfo.getLoginFailCnt() == 5) {
-			// 로그인 실패 남기기
-			loginService.createLoginFail(loginInfo.getCustNo(), "Y");
-
-//			throw new BadCredentialsException(message.getMessage("LOGN_0005"));
+		// 로그인 실패누적건수가 5회 이상이면
+		if (loginInfo.getLoginFailCnt() >= 5) {
 			throw new TsfLockedAccountException(message.getMessage("LOGN_0005"));
 		}
 
@@ -92,32 +88,20 @@ public class TsfAuthenticationProvider implements AuthenticationProvider {
 			log.info("Password is match?: {}", isMatch);
 
 			if (!isMatch) {
-				// 로그인 실패 남기기
-				loginService.createLoginFail(loginInfo.getCustNo(), "Y");
-
 				throw new BadCredentialsException(message.getMessage("LOGN_0002"));
 			}
 		} else {
 			// SNS로그인 시 로그인ID 값은 이메일로 처리했으므로
 			// loginId 값과 회원정보의 이메일 값을 비교해서 동일하면
 			if (StringUtils.isBlank(loginInfo.getSnsType()) && passwd.equals(loginInfo.getEmail())) {
-				// 로그인 실패 남기기
-				loginService.createLoginFail(loginInfo.getCustNo(), "Y");
-
 				throw new TsfEmailDuplicationException(message.getMessage("LOGN_0008"));
 			}
 		}
 
 		if (loginInfo.getCustStat().equals("20")) { // 휴면회원
-			// 로그인 실패 남기기
-			loginService.createLoginFail(loginInfo.getCustNo(), "Y");
-
 //			WfoSession.setDormantMemberNo(request, loginInfo.getCustId());
 			throw new TsfDormantAccountException(message.getMessage("LOGN_0006"));
 		} else if (loginInfo.getCustStat().equals("30")) { // 탈퇴회원
-			// 로그인 실패 남기기
-			loginService.createLoginFail(loginInfo.getCustNo(), "Y");
-
 			throw new TsfSecedeAccountException(message.getMessage("LOGN_0007"));
 		}
 

+ 10 - 7
src/main/java/com/style24/front/support/security/handler/TsfLoginFailureHandler.java

@@ -6,16 +6,16 @@ import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
-import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.core.AuthenticationException;
 import org.springframework.security.web.authentication.AuthenticationFailureHandler;
 
+import com.style24.front.biz.service.TsfLoginService;
 import com.style24.front.support.exception.TsfDormantAccountException;
 import com.style24.front.support.exception.TsfEmailDuplicationException;
 import com.style24.front.support.exception.TsfLockedAccountException;
 import com.style24.front.support.exception.TsfSecedeAccountException;
 import com.style24.front.support.exception.TsfSessionExpiredException;
-import com.style24.front.support.security.session.TsfSession;
 
 import lombok.extern.slf4j.Slf4j;
 
@@ -34,10 +34,16 @@ import com.gagaframework.web.util.GagaStringUtil;
 @Slf4j
 public class TsfLoginFailureHandler implements AuthenticationFailureHandler {
 
+	@Autowired
+	private TsfLoginService loginService;
+
 	@Override
 	public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
 		AuthenticationException exception) throws IOException, ServletException {
 
+		// 로그인 실패 남기기
+		loginService.createLoginFail(request.getParameter("loginId"), "Y");
+
 		GagaMap result = new GagaMap();
 		result.setString("message", exception.getMessage());
 
@@ -55,11 +61,8 @@ public class TsfLoginFailureHandler implements AuthenticationFailureHandler {
 			result.setString("status", "ETC_ERROR");
 		}
 
-		// 로그인실패건수 세션에 저장
-		int loginFailCnt = (StringUtils.isNotBlank(TsfSession.getAttribute("loginFailCnt")) ? Integer.parseInt(TsfSession.getAttribute("loginFailCnt")) : 0) + 1;
-		log.info("loginFailCnt: {}", loginFailCnt);
-		result.setInt("loginFailCnt", loginFailCnt);
-		TsfSession.setAttribute("loginFailCnt", String.valueOf(loginFailCnt));
+		// 로그인실패정보 조회
+		result.set("loginFailInfo", loginService.getLoginFailInfo(request.getParameter("loginId")));
 
 		GagaStringUtil.write(response, result);
 	}

+ 2 - 5
src/main/java/com/style24/front/support/security/handler/TsfLoginSuccessHandler.java

@@ -57,9 +57,9 @@ public class TsfLoginSuccessHandler implements AuthenticationSuccessHandler {
 
 		// 로그인 성공 시 로그인실패수가 0보다 크면 로그인실패수 reset
 		Integer custNo = loginDetails.getLoginInfo().getCustNo();
-		int failCnt = loginService.getLoginFailCount(custNo);
+		int failCnt = loginService.getLoginFailCount(loginDetails.getLoginInfo().getCustId());
 		if (failCnt > 0) {
-			loginService.createLoginFail(loginDetails.getLoginInfo().getCustNo(), "N");
+			loginService.createLoginFail(loginDetails.getLoginInfo().getCustId(), "N");
 		}
 
 		// 최종로그인일시 Update
@@ -122,9 +122,6 @@ public class TsfLoginSuccessHandler implements AuthenticationSuccessHandler {
 		HttpSession session = request.getSession(true);
 		session.setMaxInactiveInterval(1800);
 		session.setAttribute("session", loginDetails);
-
-		// 세션에 저장된 로그인실패건수 제거
-		session.removeAttribute("loginFailCnt");
 	}
 
 }

+ 2 - 5
src/main/java/com/style24/front/support/security/handler/TsfRememberMeSuccessHandler.java

@@ -36,9 +36,9 @@ public class TsfRememberMeSuccessHandler implements AuthenticationSuccessHandler
 
 		// 로그인 성공 시 로그인실패수가 0보다 크면 로그인실패수 reset
 		Integer custNo = loginDetails.getLoginInfo().getCustNo();
-		int failCnt = loginService.getLoginFailCount(custNo);
+		int failCnt = loginService.getLoginFailCount(loginDetails.getLoginInfo().getCustId());
 		if (failCnt > 0) {
-			loginService.createLoginFail(loginDetails.getLoginInfo().getCustNo(), "N");
+			loginService.createLoginFail(loginDetails.getLoginInfo().getCustId(), "N");
 		}
 
 		// 최종로그인일시 Update
@@ -74,9 +74,6 @@ public class TsfRememberMeSuccessHandler implements AuthenticationSuccessHandler
 		HttpSession session = request.getSession(true);
 		session.setMaxInactiveInterval(1800);
 		session.setAttribute("session", loginDetails);
-
-		// 세션에 저장된 로그인실패건수 제거
-		session.removeAttribute("loginFailCnt");
 	}
 
 }

+ 1 - 0
src/main/java/com/style24/persistence/domain/Login.java

@@ -34,6 +34,7 @@ public class Login extends TscBaseDomain {
 	private String snsType;			// SNS유형
 	private String snsJoinId;		// SNS가입ID
 	private int loginFailCnt;		// 로그인실패건수
+	private int blockSecs;			// 로그인블락시간(초)
 	private String siteCd;			// 가입사이트코드(공통코드G000)
 	private String frontGb;			// 프론트구분(P:PC, M:모바일)
 	private String ipAddr;			// IP주소

+ 6 - 2
src/main/java/com/style24/persistence/mybatis/shop/TsfCustomer.xml

@@ -13,7 +13,11 @@
 		       ) ORIGINAL
 		WHERE  NUMB BETWEEN #{pageable.startRow} AND #{pageable.endRow}
 	</sql>
-	
-	
+
+	<!-- 임시비밀번호 조회 -->
+	<select id="getTemporaryPassword" parameterType="int" resultType="String">
+		/* TsfCustomer.getTemporaryPassword */
+		SELECT CONVERT(TRUNCATE(RAND() * CAST(CONCAT(1,LPAD(0,(#{length} - 1),'0')) AS UNSIGNED),0),CHAR) AS PASSWD FROM DUAL
+	</select>
 
 </mapper>

+ 26 - 12
src/main/java/com/style24/persistence/mybatis/shop/TsfLogin.xml

@@ -21,7 +21,7 @@
 		       END                            AS SNS_JOIN_ID    /*SNS가입ID*/
 		     , IFNULL((SELECT LOGIN_FAIL_CNT
 		               FROM   TB_LOGIN_FAIL
-		               WHERE  CUST_NO = A.CUST_NO
+		               WHERE  CUST_ID = #{custId}
 		               AND    IP_ADDR = #{ipAddr}
 		               AND    SITE_CD = #{siteCd}
 		              ),0)                    AS LOGIN_FAIL_CNT /*로그인실패건수*/
@@ -47,28 +47,27 @@
 	<insert id="createLoginFail" parameterType="Login">
 		/* TsfLogin.createLoginFail */
 		INSERT INTO TB_LOGIN_FAIL (
-		       CUST_NO
+		       CUST_ID
 		     , IP_ADDR
 		     , SITE_CD
 		     , LOGIN_FAIL_CNT
-		     , REG_NO
-		     , REG_DT
-		     , UPD_NO
 		     , UPD_DT
 		)
 		VALUES (
-		       #{custNo}
+		       #{custId}
 		     , #{ipAddr}
 		     , #{siteCd}
 		     , 1
-		     , #{custNo}
-		     , NOW()
-		     , #{custNo}
 		     , NOW()
 		)
 		ON DUPLICATE KEY UPDATE
-		       LOGIN_FAIL_CNT = CASE WHEN #{loginFailYn} = 'Y' THEN LOGIN_FAIL_CNT + 1 ELSE 0 END
-		     , UPD_NO = #{custNo}
+		       LOGIN_FAIL_CNT = CASE WHEN #{loginFailYn} = 'Y' THEN
+		                                 CASE WHEN LOGIN_FAIL_CNT = 10 THEN LOGIN_FAIL_CNT
+		                                      ELSE LOGIN_FAIL_CNT + 1
+		                                 END
+		                             ELSE
+		                                 0
+		                        END
 		     , UPD_DT = NOW()
 	</insert>
 
@@ -77,12 +76,27 @@
 		/* TsfLogin.getLoginFailCount */
 		SELECT IFNULL((SELECT LOGIN_FAIL_CNT
 		               FROM   TB_LOGIN_FAIL
-		               WHERE  CUST_NO = #{custNo}
+		               WHERE  CUST_ID = #{custId}
 		               AND    IP_ADDR = #{ipAddr}
 		               AND    SITE_CD = #{siteCd}
 		              ),0) AS CNT
 		FROM   DUAL
 	</select>
+	
+	<!-- 로그인실패정보 조회 -->
+	<select id="getLoginFailInfo" parameterType="Login" resultType="Login">
+		/* TsfLogin.getLoginFailInfo */
+		SELECT LOGIN_FAIL_CNT
+		     , CASE WHEN LOGIN_FAIL_CNT <![CDATA[>=]]> 10 THEN
+		                180 - TIMESTAMPDIFF(SECOND,UPD_DT,NOW())
+		            ELSE
+		                0
+		       END            AS BLOCK_SECS /*로그인블락시간(초)*/
+		FROM   TB_LOGIN_FAIL
+		WHERE  CUST_ID = #{custId}
+		AND    IP_ADDR = #{ipAddr}
+		AND    SITE_CD = #{siteCd}
+	</select>
 
 	<!-- 최종로그인일시 Update -->
 	<update id="updateLastLoginDate" parameterType="Integer">

+ 12 - 6
src/main/resources/config/application-locd.yml

@@ -25,26 +25,32 @@ domain:
     uximage: //ldfront.style24.com
 
 upload:
+    dext.target.path: /WIDE/workspace/files/data/style24/dext
     default:
-        target.path: /WIDE/workspace/files/data
+        target.path: /WIDE/workspace/files/data/style24
         max.size: 10
         allow.extension: jpg|gif|jpeg|png|bmp|txt|doc|docx|ppt|pptx|xls|xlsx|hwp|pdf
         view: //ldimage.style24.com
     goods:
-        target.path: /WIDE/workspace/files/data/goods
+        target.path: /WIDE/workspace/files/data/style24/Upload/ProductImage
         max.size: 10
-        allow.extension: jpg|gif|jpeg|png
-        view: //image.style24.com/speedy_image-wivismall/goods
+        allow.extension: jpg|gif|jpeg
+        view: //ldimage.style24.com/Upload/ProductImage
     image:
-        target.path: /WIDE/workspace/files/data
+        target.path: /WIDE/workspace/files/data/style24
         max.size: 10
         allow.extension: jpg|gif|jpeg|png
         view: //ldimage.style24.com
     excel:
-        target.path: /WIDE/workspace/files/data/excel
+        target.path: /WIDE/workspace/files/data/style24/excel
         max.size: 10
         allow.extension: xls|xlsx
         view: //ldimage.style24.com/excel
+    sample:
+        target.path: /WIDE/workspace/files/data/style24/sample
+        max.size: 10
+        allow.extension: txt|doc|docx|ppt|pptx|xls|xlsx|hwp|pdf
+        view: //ldimage.style24.com/sample
 
 download.path: /WIDE/workspace/files/data
 

+ 4 - 0
src/main/resources/config/application.yml

@@ -31,6 +31,10 @@ certify:
         id: G2860
         pwd: A2G93CK87ZP8
         callback: /customer/nice/certify/callback
+    ipin:
+        id: A621
+        pwd: 73350165
+        callback: /customer/nice/certify/callback
 
 # 네이버 API
 naver:

BIN
src/main/webapp/WEB-INF/lib/IPIN2Client.jar


+ 54 - 23
src/main/webapp/WEB-INF/views/web/SigninFormWeb.html

@@ -34,7 +34,7 @@
 							<label class="input_label sr-only">아이디</label>
 							<div class="ui_col_12">
 								<div class="input_wrap"> 
-									<input type="text" name="loginId" placeholder="아이디" class="form_control" minlength="4" maxlength="20" required="required" data-valid-name="아이디"/>
+									<input type="text" name="loginId" placeholder="아이디" class="form_control" minlength="4" maxlength="12" required="required" data-valid-type="alphaNumeric" data-valid-name="아이디"/>
 								</div>
 							</div>
 						</div>
@@ -42,7 +42,7 @@
 							<label class="input_label sr-only">비밀번호</label>
 							<div class="ui_col_12">
 								<div class="input_wrap"> 
-									<input type="password" name="passwd" class="form_control" placeholder="비밀번호 8자 ~ 20자 입력" maxlength="20" required="required" data-valid-name="비밀번호"/>
+									<input type="password" name="passwd" class="form_control" placeholder="비밀번호 8자 ~ 20자 입력" minlength="8" maxlength="20" required="required" data-valid-name="비밀번호"/>
 								</div>
 							</div>
 						</div>
@@ -59,40 +59,36 @@
 						</div>
 						<!-- case (회원 아이디 또는 비밀번호가 일치하지 않을때,보안문자 입력시) -->
 						<div class="help_block">
-							<!-- 회원 아이디 또는 비밀번호가 일치하지 않을때 -->
-							<p class="t_err t_err_login_fail" style="display: none;">
-								<span id="not_exist">회원 아이디 또는 비밀번호가 일치하지 않습니다.</span><br/>
-								(10회 이상 실패하면 180초 동안 로그인이 불가능 합니다.)<br/>
-								<span id="login_fail_cnt">4</span>회 실패 / 잔여 : <span id="login_remain_cnt">6</span>회 / <span>180</span>초 남음
-							</p>
 							<!-- //회원 아이디 또는 비밀번호가 일치하지 않을때 -->
 							<!-- 보안문자 입력시 -->
 							<div class="captcha mt40" style="display: none;"> <!-- 캡차영역 -->
 								<ul>
 									<li class="captcha_box"> <!-- 캡차이미지 -->
+										<img src="" id="imgCaptcha"/>
 									</li>
 									<li class="captcha_btn_dual">
-										<button type="button" id="play_audio">새로고침</button>
+										<button type="button" id="play_audio" onclick="fnReloadCaptchaImage();">새로고침</button>
 										<button type="button" id="swap_captcha">음성듣기</button>
 									</li>
 									<li class="captcha_area">
 										<label for="captcha" id="label_captcha_area">보안문자 입력</label>
-										<input type="text" id="captcha" name="captcha" title="문자입력">
+										<input type="text" name="captcha" title="문자입력">
 									</li>
 								</ul>
 							</div>
-							<p class="t_err t_err_captcha" style="display: none;">
-								보안문자 입력을 다시 시도해 주세요.<br/>
-								(10회 이상 실패하면 300초 동안 로그인이 불가능 합니다.)<br/>
-								<span>10</span>회 실패 / 잔여 : <span>0</span>회 / <span>180</span>초 남음
-							</p>
 							<!-- //보안문자 입력시 -->
+							<!-- 회원 아이디 또는 비밀번호가 일치하지 않을때 -->
+							<p class="t_err t_err_login_fail" style="display: none;">
+								<span id="err_msg">보안문자 입력을 다시 시도해 주세요.</span><br/>
+								(10회 이상 실패하면 180초 동안 로그인이 불가능 합니다.)<br/>
+								<span id="login_fail_cnt">4</span>회 실패 / 잔여 : <span id="login_remain_cnt">6</span>회<span id="blockSecs1" style="display: none;"> / <span id="blockSecs2">180</span>초 남음</span>
+							</p>
 						</div>
 						<!-- //case (회원 아이디 또는 비밀번호가 일치하지 않을때,보안문자 입력시) -->
 						<div class="ui_row mt40">
 							<div class="ui_col_12">
-<!-- 								<button class="btn btn_dark btn_block" onclick="fnLogin();"><span>로그인</span></button> -->
-								<a class="btn btn_dark btn_block" onclick="fnLogin();"><span>로그인</span></a>
+<!-- 								<button class="btn btn_dark btn_block" id="btnLogin"><span>로그인</span></button> -->
+								<a class="btn btn_dark btn_block" id="btnLogin"><span>로그인</span></a>
 							</div>
 						</div>
 						<div class="sns_wrap">
@@ -131,8 +127,20 @@
 /*<![CDATA[*/
 	let ckLoginId = "ckLoginId";
 
+	// 로그인블락시간(초) 설정
+	let fnSetLoginBlockTime = function() {
+		let blockSecs = Number($("#blockSecs2").html()) - 1;
+		$("#blockSecs2").html(blockSecs);
+		if (blockSecs == 0) {
+			clearTimeout(fnSetLoginBlockTime);
+			$('#btnLogin').attr('disabled',false);
+		} else {
+			setTimeout(fnSetLoginBlockTime, 1000);
+		}
+	}
+	
 	// 로그인
-	var fnLogin = function() {
+	$('#btnLogin').on('click', function() {
 		if (!gagajf.validation($('#loginForm'))) {
 			return;
 		}
@@ -146,14 +154,32 @@
 			, function(result) {
 				if (result.status != 'OK') {
 					if (!gagajf.isNull(result.message)) {
-						$("#not_exist").html(result.message);
-						$("#login_fail_cnt").html(result.loginFailCnt);
-						$("#login_remain_cnt").html(10 - Number(result.loginFailCnt));
+						let loginFailCnt = Number(result.loginFailInfo.loginFailCnt);
+						
+						$("#err_msg").html(result.message);
+						$("#login_fail_cnt").html(loginFailCnt);
+						$("#login_remain_cnt").html(10 - loginFailCnt);
 						$(".t_err_login_fail").show();
+						
+						if (loginFailCnt >= 5 && loginFailCnt < 10) {
+							// 비밀번호 5회 이상 틀린 경우 캡챠 노출
+							$('.captcha').show();
+						} else if (loginFailCnt >= 10) {
+							$('.captcha').hide();
+							
+							// 비밀번호 10회 이상 틀린 경우 로그인 블락
+							let blockSecs = Number(result.loginFailInfo.blockSecs);
+							if (blockSecs > 0) {
+								$("#blockSecs2").html(blockSecs);
+								fnSetLoginBlockTime();
+								$("#blockSecs1").show();
+								$('#btnLogin').attr('disabled',true);
+							}
+						}
 					}
 					
 					if (result.status == 'PWD_5WRONG') {
-						// 비밀번호 5회 이상 틀린 경우
+						// Do nothing
 					} else if (result.status == 'DORMANT_CUST') {
 						// 휴면회원
 						//cfnGoToPage(_PAGE_DORMANT_GUIDE);
@@ -185,7 +211,7 @@
 // 				}
 			}
 			, 'json');
-	}
+	});
 	
 	// Save ID
 	$('#chkSaveId').on('click', function() {
@@ -200,6 +226,11 @@
 		}
 	});
 	
+	// 캡챠 이미지 로딩
+	let fnReloadCaptchaImage = function() {
+		$('#imgCaptcha').attr('src', '/common/captcha.do?dummy=' + new Date());
+	}
+	
 	// 카카오 로그인
 	var fnLoginKakao = function() {
 		document.location.href = _frontUrl + '/signin/kakologin';

+ 0 - 399
src/main/webapp/WEB-INF/views/web/customer/FindIdAndPwdFormWeb.html

@@ -1,399 +0,0 @@
-<!DOCTYPE html>
-<html lang="ko"
-	xmlns:th="http://www.thymeleaf.org"
-	xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
-	layout:decorator="web/common/layout/DefaultLayoutWeb">
-<!--
- *******************************************************************************
- * @source  : FindIdAndPwdFormWeb.html
- * @desc    : 아이디 비번 찾기 Page
- *============================================================================
- * STYLE24
- * Copyright(C) 2021 TSIT, All rights reserved.
- *============================================================================
- * VER  DATE         AUTHOR      DESCRIPTION
- * ===  ===========  ==========  =============================================
- * 1.0  2021.02.05   jsshin     최초 작성
- *******************************************************************************
- -->
-<body>
-
-<th:block layout:fragment="content">
-<div id="container" class="container mb">
-	<div class="wrap">
-		<div class="content find">
-			<div class="cont_head">
-				<h3>style24</h3>
-			</div>
-			<div class="cont_body">
-				<form class="form_wrap form_col_c" role="form">
-					<div class="form_head">
-						<h4>아이디&#47;비밀번호 찾기</h4>
-					</div>
-					<div class="registration_nav">
-						<ul>
-							<li class="active"><a href="javascript:void(0)">아이디 찾기</a></li>
-							<li><a href="javascript:void(0)">비밀번호 찾기</a></li>
-						</ul>
-					</div>
-					<div class="registration_tap">
-						<div class="form_group">
-							<!-- 아이디찾기일경우 -->
-							<div class="foldGroup checkcase">
-								<ul>
-									<li>
-										<form class="form_wrap" role="form">
-											<div class="fold_head">
-												<a href="javascript:void(0)">
-													<div>
-														<div class="fold_tit">
-															<span>회원정보로 찾기</span>
-														</div>
-													</div>
-												</a>
-											</div>
-											<div class="fold_cont">
-												<div class="txt mb30">
-													<p>등록된 내 회원정보로 찾을 수 있습니다.</p>
-												</div>
-												<div class="form_field">
-													<label class="input_label sr-only">이름</label>
-													<div class="ui_col_12">
-														<div class="input_wrap">
-															<input type="text" name="userName" placeholder="이름" id="txtName" class="form_control">
-														</div>
-													</div>
-												</div>
-												<div class="form_field">
-													<label class="input_label sr-only">생년월일 8자리 (예:19880912)</label>
-													<div class="ui_col_12">
-														<div class="input_wrap">
-															<input type="text" name="userBirth" placeholder="생년월일 8자리 (예:19880912)" id="txtBirth" class="form_control">
-														</div>
-													</div>
-												</div>
-												<div class="form_field">
-													<label class="input_label sr-only">이메일</label>
-													<div class="ui_col_12">
-														<div class="input_wrap">
-															<input type="text" name="userEmail" placeholder="이메일" id="txtEmail" class="form_control">
-														</div>
-													</div>
-												</div>
-												<div class="btn_group_block ui_row mt20">
-													<div class="ui_col_12">
-														<button class="btn btn_dark btn_block"><span>확인</span></button>
-													</div>
-												</div>
-											</div>
-										</form>
-									</li>
-									<li>
-										<form class="form_wrap" role="form">
-											<div class="fold_head">
-												<a href="javascript:void(0)">
-													<div>
-														<div class="fold_tit" style="width: inherit;">
-															<span style="width: inherit;">휴대폰 본인인증으로 찾기</span>
-														</div>
-													</div>
-												</a>
-											</div>
-											<div class="fold_cont">
-												<div class="txt">
-													<p>회원님의 명의로 등록된 휴대폰으로 본인확인을 진행합니다.</p>
-												</div>
-												<div class="ui_row mt20">
-													<div class="ui_col_12">
-														<button class="btn btn_dark btn_block"><span>본인명의 휴대폰으로 인증</span></button>
-													</div>
-												</div>
-											</div>
-										</form>
-									</li>
-									<li>
-										<form class="form_wrap" role="form">
-											<div class="fold_head">
-												<a href="javascript:void(0)">
-													<div>
-														<div class="fold_tit" style="width: inherit;">
-															<span style="width: inherit;">아이핀 인증으로 찾기</span>
-														</div>
-													</div>
-												</a>
-											</div>
-											<div class="fold_cont">
-												<div class="txt">
-													<p>아이핀 인증을 통해 찾을 수 있습니다.</p>
-												</div>
-												<div class="ui_row mt20">
-													<div class="ui_col_12">
-														<button class="btn btn_dark btn_block"><span>아이핀 인증</span></button>
-													</div>
-												</div>
-											</div>
-										</form>
-									</li>
-								</ul>
-							</div>
-							<!-- //아이디찾기일경우 -->
-							<!-- 아이디찾기 성공일경우 -->
-							<div class="find_result clear">
-								<div class="form_info">
-									<span class="ico_content_find"></span>
-									<p>아이디 찾기 결과 안내</p>
-								</div>
-								<div class="form_print_bar mt40">
-									<ul>
-										<li>
-											<span class="t_span">아이디</span>
-											<span class="c_primary bold" data-font="lato">I***D1</span>
-										</li>
-										<li>
-											<span class="t_span">가입일자</span>
-											<span class="bold" data-font="lato">2020.12.22</span>
-										</li>
-										<li>
-											<span class="t_span">가입경로</span>
-											<span class="bold" data-font="lato">YES24 연동</span>
-										</li>
-									</ul>
-								</div>
-								<div class="btn_group_block btn_group_md ui_row">
-									<div class="ui_col_12">
-										<button class="btn btn_dark btn_block"><span>로그인 하기</span></button>
-									</div>
-								</div>
-							</div>
-							<!-- //아이디찾기 성공일경우 -->
-							<!-- 회원정보로 아이디찾기 실패일경우 -->
-							<div class="find_result clear">
-								<div class="form_info">
-									<span class="ico_content_none"></span>
-									<p>입력한 정보와 일치하는 아이디가 존재하지 않습니다.</p>
-									<p class="t_info mt10">
-										정확한 확인을 위해 휴대폰 인증/아이핀 인증을 통한<br>아이디 찾기를 진행해 주세요.
-									</p>
-								</div>
-								<div class="btn_group_block btn_group_md ui_row">
-									<div class="ui_col_6">
-										<button class="btn btn_primary btn_block"><span>회원가입</span></button>
-									</div>
-									<div class="ui_col_6">
-										<button class="btn btn_dark btn_block"><span>다시 찾기</span></button>
-									</div>
-								</div>
-							</div>
-							<!-- //회원정보로 아이디찾기 실패일경우 -->
-							<!-- 휴대폰,아이핀 본인인증으로 아이디찾기 실패일경우 -->
-							<div class="find_result clear">
-								<div class="form_info">
-									<span class="ico_content_none"></span>
-									<p>입력한 정보와 일치하는 아이디가 존재하지 않습니다.</p>
-									<p class="t_info mt10">
-										<span class="c_primary">STYLE24의 새로운 가족이 되어 주세요!</span>
-									</p>
-								</div>
-								<div class="btn_group_block btn_group_md ui_row">
-									<div class="ui_col_12">
-										<button class="btn btn_primary btn_block"><span>회원가입</span></button>
-									</div>
-								</div>
-							</div>
-							<!-- //휴대폰,아이핀 본인인증으로 아이디찾기 실패일경우 -->
-						</div>
-						<div class="form_group" >
-							<!-- 비밀번호찾기일경우 -->
-							<div class="foldGroup checkcase">
-								<ul>
-									<li>
-										<form class="form_wrap" role="form">
-											<div class="fold_head">
-												<a href="javascript:void(0)">
-													<div>
-														<div class="fold_tit" style="width: inherit;">
-															<span style="width: inherit;">회원정보로 찾기</span>
-														</div>
-													</div>
-												</a>
-											</div>
-											<div class="fold_cont">
-												<div class="txt mb30">
-													<p>등록된 내 회원정보로 찾을 수 있습니다.</p>
-												</div>
-												<div class="form_field form_full">
-													<label class="input_label sr-only">아이디</label>
-													<div class="ui_col_12">
-														<div class="input_wrap">
-															<input type="text" name="userId" placeholder="아이디" id="txtId" class="form_control">
-															<button type="button" class="btn btn_primary"><span>확인</span></button>
-														</div>
-													</div>
-												</div>
-												<div class="form_field">
-													<label class="input_label sr-only">이름</label>
-													<div class="ui_col_12">
-														<div class="input_wrap">
-															<input type="text" name="userName" placeholder="이름" id="txtName" class="form_control">
-														</div>
-													</div>
-												</div>
-												<div class="form_field">
-													<label class="input_label sr-only">이메일</label>
-													<div class="ui_col_12">
-														<div class="input_wrap">
-															<input type="text" name="userEmail" placeholder="이메일" id="email" class="form_control">
-														</div>
-													</div>
-												</div>
-												<div class="btn_group_block ui_row mt20">
-													<div class="ui_col_12">
-														<button class="btn btn_dark btn_block"><span>확인</span></button>
-													</div>
-												</div>
-											</div>
-										</form>
-									</li>
-									<li>
-										<form action="" class="form_wrap" role="form">
-											<div class="fold_head">
-												<a href="javascript:void(0)">
-													<div>
-														<div class="fold_tit" style="width: inherit;">
-															<span style="width: inherit;">휴대폰 본인인증으로 찾기</span>
-														</div>
-													</div>
-												</a>
-											</div>
-											<div class="fold_cont">
-												<div class="txt">
-													<p>회원님의 명의로 등록된 휴대폰으로 본인확인을 진행합니다.</p>
-												</div>
-												<div class="ui_row mt20">
-													<div class="ui_col_12">
-														<button class="btn btn_dark btn_block"><span>본인명의 휴대폰으로 인증</span></button>
-													</div>
-												</div>
-											</div>
-										</form>
-									</li>
-									<li>
-										<form action="" class="form_wrap" role="form">
-											<div class="fold_head">
-												<a href="javascript:void(0)">
-													<div>
-														<div class="fold_tit" style="width: inherit;">
-															<span style="width: inherit;">아이핀 인증으로 찾기</span>
-														</div>
-													</div>
-												</a>
-											</div>
-											<div class="fold_cont">
-												<div class="txt">
-													<p>아이핀 인증을 통해 찾을 수 있습니다.</p>
-												</div>
-												<div class="ui_row mt20">
-													<div class="ui_col_12">
-														<button class="btn btn_dark btn_block"><span>아이핀 인증</span></button>
-													</div>
-												</div>
-											</div>
-										</form>
-									</li>
-								</ul>
-							</div>
-							<!-- //비밀번호찾기일경우 -->
-							<!-- 비밀번호 재설정 -->
-							<div class="find_result clear">
-								<div class="form_info">
-									<span class="ico_content_security"></span>
-									<p>안전을 위해 비밀번호를 변경하신 후 이용이 가능합니다.</p>
-								</div>
-								<div class="form_field mt40">
-									<label class="input_label sr-only">신규 비밀번호</label>
-									<div class="ui_col_12">
-										<input type="password" name="userPassword" placeholder="신규 비밀번호" id="txtPassword">
-										<!-- case (사용불가 비밀번호일경우,사용가능한 비밀번호일경우) -->
-										<div class="help_block">
-											<!-- 사용불가 비밀번호일경우 -->
-											<p class="mt10">
-												<span class="c_black2"><i class="ico ico_check black mr5"></i>영문(대/소문자), 숫자, 특수문자 중 2가지 이상 조합(8~20자)</span><br>
-												<span class="c_red2"><i class="ico ico_check red mr5"></i>4개이상 연속되거나 동일한 문자/숫자 제외</span><br>
-												<span class="c_gray"><i class="ico ico_check gray mr5"></i>아이디 제외</span>
-											</p>
-											<!-- //사용불가 비밀번호일경우 -->
-											<!-- 사용가능한 비밀번호일경우 -->
-											<p class="mt10">
-												<span class="c_black2"><i class="ico ico_check black mr5"></i>사용 가능한 비밀번호입니다</span>
-											</p>
-											<!-- //사용가능한 비밀번호일경우 -->
-										</div>
-										<!-- //case (사용불가 비밀번호일경우,사용가능한 비밀번호일경우) -->
-									</div>
-								</div>
-								<div class="form_field">
-									<label class="input_label sr-only">비밀번호 확인</label>
-									<div class="ui_col_12">
-										<input type="password" name="userConfirm" placeholder="비밀번호 확인" id="txtConfirm">
-										<!-- case (비밀번호확인 틀렸을경우,비밀번호 일치할경우) -->
-										<div class="help_block">
-											<!-- 비밀번호확인 틀렸을경우 -->
-											<p class="t_err">
-												새 비밀번호가 일치하지 않습니다.
-											</p>
-											<!-- //비밀번호확인 틀렸을경우 -->
-											<!-- 비밀번호 일치할경우 -->
-											<p class="mt10">
-                                                    <span class="c_black2">
-                                                        <i class="ico ico_check black mr5"></i>새 비밀번호가 일치합니다.
-                                                    </span>
-											</p>
-											<!-- //비밀번호 일치할경우 -->
-										</div>
-										<!-- //case (비밀번호확인 틀렸을경우,비밀번호 일치할경우) -->
-									</div>
-								</div>
-								<div class="btn_group_block btn_group_md ui_row">
-									<div class="ui_col_12">
-										<button class="btn btn_dark btn_block"><span>변경 후 다시 로그인</span></button>
-									</div>
-								</div>
-							</div>
-							<!-- //비밀번호 재설정 -->
-							<!-- 임시비밀번호 발급 -->
-							<div class="find_result clear">
-								<div class="form_info">
-									<span class="ico_content_mail"></span>
-									<p>아래의 이메일로 임시비밀번호가 발급되었습니다.</p>
-									<p class="t_info mt10">
-										로그인 시 비밀번호를 새로 설정하신 후 이용하실 수 있습니다.
-									</p>
-								</div>
-								<div class="form_print_bar mt40">
-									<p class="c_primary bold" data-font="lato">a****c@gmail.com</p>
-								</div>
-								<div class="btn_group_block btn_group_md ui_row">
-									<div class="ui_col_12">
-										<button class="btn btn_dark btn_block"><span>로그인 하기</span></button>
-									</div>
-								</div>
-							</div>
-							<!-- //임시비밀번호 발급 -->
-						</div>
-					</div>
-				</form>
-			</div>
-		</div>
-	</div>
-</div>
-
-<script th:inline="javascript">
-/*<![CDATA[*/
-
-/*]]>*/
-</script>
-
-</th:block>
-
-</body>
-</html>

+ 333 - 0
src/main/webapp/WEB-INF/views/web/customer/FindIdFormWeb.html

@@ -0,0 +1,333 @@
+<!DOCTYPE html>
+<html lang="ko"
+	xmlns:th="http://www.thymeleaf.org"
+	xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
+	layout:decorator="web/common/layout/DefaultLayoutWeb">
+<!--
+ *******************************************************************************
+ * @source  : FindIdFormWeb.html
+ * @desc    : 아이디 비번 찾기 Page
+ *============================================================================
+ * STYLE24
+ * Copyright(C) 2021 TSIT, All rights reserved.
+ *============================================================================
+ * VER  DATE         AUTHOR      DESCRIPTION
+ * ===  ===========  ==========  =============================================
+ * 1.0  2021.02.05   jsshin     최초 작성
+ *******************************************************************************
+ -->
+<body>
+
+<th:block layout:fragment="content">
+<div id="container" class="container mb">
+	<div class="wrap">
+		<div class="content find">
+			<div class="cont_head">
+				<h3>style24</h3>
+			</div>
+			<div class="cont_body">
+				<div class="form_wrap form_col_c">
+					<div class="form_head">
+						<h4>아이디&#47;비밀번호 찾기</h4>
+					</div>
+					<div class="registration_nav">
+						<ul>
+							<li class="active"><a href="javascript:void(0)" onclick="cfnGoToPage(_PAGE_CUSTOMER_ID_FIND);">아이디 찾기</a></li>
+							<li><a href="javascript:void(0)" onclick="cfnGoToPage(_PAGE_CUSTOMER_PWD_FIND);">비밀번호 찾기</a></li>
+						</ul>
+					</div>
+					<div class="registration_tap">
+						<div class="form_group" style="display: block;">
+							<!-- 아이디찾기일경우 -->
+							<div id="searchDiv" class="foldGroup checkcase">
+								<ul>
+									<li>
+										<form id="searchCustInfo" name="searchCustInfo" class="form_wrap" method="post">
+											<div class="fold_head">
+												<a href="javascript:void(0)">
+													<div>
+														<div class="fold_tit">
+															<span>회원정보로 찾기</span>
+														</div>
+													</div>
+												</a>
+											</div>
+											<div class="fold_cont">
+												<div class="txt mb30">
+													<p>등록된 내 회원정보로 찾을 수 있습니다.</p>
+												</div>
+												<div class="form_field">
+													<label class="input_label sr-only">이름</label>
+													<div class="ui_col_12">
+														<div class="input_wrap">
+															<input type="text" id="custNm" name="custNm" placeholder="이름" class="form_control" maxlength="30"/>
+														</div>
+													</div>
+												</div>
+												<div class="form_field">
+													<label class="input_label sr-only">생년월일 8자리 (예:19880912)</label>
+													<div class="ui_col_12">
+														<div class="input_wrap">
+															<input type="text" id="birthYmd" name="birthYmd" placeholder="생년월일 8자리 (예:19880912)" class="form_control" maxlength="8" data-valid-type="numeric"/>
+														</div>
+													</div>
+												</div>
+												<div class="form_field">
+													<label class="input_label sr-only">이메일</label>
+													<div class="ui_col_12">
+														<div class="input_wrap">
+															<input type="text" id="email" name="email" placeholder="이메일" class="form_control" maxlength="30"/>
+														</div>
+													</div>
+												</div>
+												<div class="btn_group_block ui_row mt20">
+													<div class="ui_col_12">
+														<button type="button" id="btnInfoConfirm" class="btn btn_dark btn_block">
+															<span>확인</span>
+														</button>
+													</div>
+												</div>
+											</div>
+										</form>
+									</li>
+									<li>
+										<div class="fold_head">
+											<a href="javascript:void(0)">
+												<div>
+													<div class="fold_tit" style="width: inherit;">
+														<span style="width: inherit;">휴대폰 본인인증으로 찾기</span>
+													</div>
+												</div>
+											</a>
+										</div>
+										<div class="fold_cont">
+											<div class="txt">
+												<p>회원님의 명의로 등록된 휴대폰으로 본인확인을 진행합니다.</p>
+											</div>
+											<div class="ui_row mt20">
+												<div class="ui_col_12">
+													<button type="button" id="btnCellPhoneCertify" class="btn btn_dark btn_block">
+														<span>본인명의 휴대폰으로 인증</span>
+													</button>
+												</div>
+											</div>
+										</div>
+									</li>
+									<li>
+										<div class="fold_head">
+											<a href="javascript:void(0)">
+												<div>
+													<div class="fold_tit" style="width: inherit;">
+														<span style="width: inherit;">아이핀 인증으로 찾기</span>
+													</div>
+												</div>
+											</a>
+										</div>
+										<div class="fold_cont">
+											<div class="txt">
+												<p>아이핀 인증을 통해 찾을 수 있습니다.</p>
+											</div>
+											<div class="ui_row mt20">
+												<div class="ui_col_12">
+													<button type="button" id="btnIpinCertify" class="btn btn_dark btn_block">
+														<span>아이핀 인증</span>
+													</button>
+												</div>
+											</div>
+										</div>
+									</li>
+								</ul>
+							</div>
+							<!-- //아이디찾기일경우 -->
+							<!-- 아이디찾기 성공일경우 -->
+							<div id="succeedCustId" class="find_result clear" style="display:none;">
+								<div class="form_info">
+									<span class="ico_content_find"></span>
+									<p>아이디 찾기 결과 안내</p>
+								</div>
+								<div class="form_print_bar mt40">
+									<ul>
+										<li>
+											<span class="t_span">아이디</span>
+											<span id="resultId" name="resultId"  class="c_primary bold" data-font="lato"></span>
+										</li>
+										<li>
+											<span class="t_span">가입일자</span>
+											<span id="joinDt" name="joinDt" class="bold" data-font="lato"></span>
+										</li>
+										<li id="liJoinPath" style="display: none;">
+											<span class="t_span">가입경로</span>
+											<span id="joinPath" name="joinPath" class="bold" data-font="lato"></span>
+										</li>
+									</ul>
+								</div>
+								<div class="btn_group_block btn_group_md ui_row">
+									<div class="ui_col_12">
+										<button type="button" class="btn btn_dark btn_block">
+											<span>로그인 하기</span>
+										</button>
+									</div>
+								</div>
+							</div>
+							<!-- //아이디찾기 성공일경우 -->
+							<!-- 회원정보로 아이디찾기 실패일경우 -->
+							<div id="failCustId" class="find_result clear" style="display: none;">
+								<div class="form_info">
+									<span class="ico_content_none"></span>
+									<p>입력한 정보와 일치하는 아이디가 존재하지 않습니다.</p>
+									<p class="t_info mt10">
+										정확한 확인을 위해 휴대폰 인증/아이핀 인증을 통한<br>아이디 찾기를 진행해 주세요.
+									</p>
+								</div>
+								<div class="btn_group_block btn_group_md ui_row">
+									<div class="ui_col_6">
+										<button type="button" class="btn btn_primary btn_block" onclick="cfnGoToPage(_PAGE_CUSTOMER_JOIN);">
+											<span>회원가입</span>
+										</button>
+									</div>
+									<div class="ui_col_6">
+										<button type="button" class="btn btn_dark btn_block" onclick="cfnGoToPage(_PAGE_CUSTOMER_ID_FIND);">
+											<span>다시 찾기</span>
+										</button>
+									</div>
+								</div>
+							</div>
+							<!-- //회원정보로 아이디찾기 실패일경우 -->
+							<!-- 휴대폰,아이핀 본인인증으로 아이디찾기 실패일경우 -->
+							<div id="failAuthentication" class="find_result clear" style="display: none;">
+								<div class="form_info">
+									<span class="ico_content_none"></span>
+									<p>입력한 정보와 일치하는 아이디가 존재하지 않습니다.</p>
+									<p class="t_info mt10">
+										<span class="c_primary">STYLE24의 새로운 가족이 되어 주세요!</span>
+									</p>
+								</div>
+								<div class="btn_group_block btn_group_md ui_row">
+									<div class="ui_col_12">
+										<button type="button" class="btn btn_primary btn_block" onclick="cfnGoToPage(_PAGE_CUSTOMER_JOIN);">
+											<span>회원가입</span>
+										</button>
+									</div>
+								</div>
+							</div>
+							<!-- //휴대폰,아이핀 본인인증으로 아이디찾기 실패일경우 -->
+						</div>
+					</div>
+				</div>
+			</div>
+		</div>
+	</div>
+</div>
+
+<script th:src="@{'/ux/customer/customer.js?v=' + ${#calendars.format(#calendars.createNow(), 'yyyyMMddHHmmss')}}" src="/ux/customer/customer.js"></script>
+<script th:inline="javascript">
+/*<![CDATA[*/
+
+	// 회원정보로 아이디 찾기
+	$('#btnInfoConfirm').on('click', function() {
+		let custInfo = $('#searchCustInfo').serializeObject();
+
+		if (gagajf.isNull(custInfo.custNm)) {
+			mcxDialog.alert('이름을 형식에 맞게 입력해주세요.');
+			return;
+		}
+
+		if (gagajf.isNull(custInfo.email)) {
+			mcxDialog.alert('이메일을 입력하여 주세요.');
+			return;
+		}
+
+		if (!fnCheckValidationEmail(custInfo.email)) {
+			mcxDialog.alert('이메일 형식에 맞게 입력해주세요.');
+			return;
+		}
+		custInfo.authMethod = 'custInfo';
+
+		let jsonData = JSON.stringify(custInfo);
+		//console.log('jsonData', jsonData);
+		ajaxJsonSubmit('/customer/id/find', jsonData, fnInfoConfirmCallBack);
+	});
+
+	// 휴대폰 인증
+	$('#btnCellPhoneCertify').on('click', function () {
+		cfnOpenCellphoneCertify();
+	});
+
+	// 아이핀 인증
+	$('#btnIpinCertify').on('click', function () {
+		cfnOpenIpinCertify();
+	});
+
+	// 나이스 본인인증 후 콜백
+	var fnNiceCallBack = function(encData, authMethod) {
+		if (!gagajf.isNull(encData)) {
+			let custInfo = {};
+			custInfo.encData = encData;
+			custInfo.authMethod = authMethod;
+			let jsonData = JSON.stringify(custInfo);
+			ajaxJsonSubmit('/customer/id/find', jsonData, fnInfoConfirmCallBack)
+		}
+	};
+
+	// 찾기결과
+	var fnInfoConfirmCallBack = function (result) {
+		$('#searchDiv').hide();
+		if (result.isFind) {
+			fnGetDisplaySucc(result.authMethod, result);
+		} else {
+			fnGetDisplayFail(result.authMethod);
+		}
+	};
+
+	// 찾기성공
+	var fnGetDisplaySucc = function (authMethod, custInfo) {
+		$('#resultId').text(custInfo.maskingCustId);
+		$('#joinDt').text(fnToDateFormat(custInfo.joinDt));
+		let joinPath = fnSnsJoinPath(custInfo); // 가입경로 : 직접이면 표시 안함, 간편가입 연동 표시
+		if (!gagajf.isNull(joinPath)) {
+			$('#liJoinPath').show();
+			$('#joinPath').text(joinPath);
+		}
+		$('#succeedCustId').show();
+	};
+
+	// 찾기실패
+	var fnGetDisplayFail = function (authMethod) {
+		$('.form_head').hide();
+		$('.registration_nav').hide();
+		if (authMethod === 'custInfo') {
+			$('#failCustId').show();
+		}
+		if (authMethod === 'mobile' || authMethod === 'ipin') {
+			$('#failAuthentication').show();
+		}
+	};
+
+	// 가입경로
+	var fnSnsJoinPath = function (custInfo) {
+		let snsType = '';
+		if (!gagajf.isNull(custInfo.ysJoinDt)) {
+			snsType += 'YES24로 연동';
+		}
+		if (!gagajf.isNull(custInfo.nvJoinDt)) {
+			if (!gagajf.isNull(snsType)) {
+				snsType += '/'
+			}
+			snsType = '네이버로 연동'
+		}
+		if (!gagajf.isNull(custInfo.kkJoinDt)) {
+			if (!gagajf.isNull(snsType)) {
+				snsType += '/'
+			}
+			snsType += '카카오로 연동';
+		}
+		return snsType;
+	};
+
+/*]]>*/
+</script>
+
+</th:block>
+
+</body>
+</html>

+ 0 - 96
src/main/webapp/WEB-INF/views/web/customer/FindIdResultFormWeb.html

@@ -1,96 +0,0 @@
-<!DOCTYPE html>
-<html lang="ko"
-	xmlns:th="http://www.thymeleaf.org"
-	xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
-	layout:decorator="web/common/layout/DefaultLayoutWeb">
-<!--
- *******************************************************************************
- * @source  : FindIdResultFormWeb.html
- * @desc    : 아이디 찾기 결과 안내 Page
- *============================================================================
- * STYLE24
- * Copyright(C) 2021 TSIT, All rights reserved.
- *============================================================================
- * VER  DATE         AUTHOR      DESCRIPTION
- * ===  ===========  ==========  =============================================
- * 1.0  2021.02.05   jsshin     최초 작성
- *******************************************************************************
- -->
-<body>
-
-<th:block layout:fragment="content">
-<div id="container" class="container mb">
-	<div class="wrap">
-		<div class="content find_complete"> <!-- 페이지특정 클래스 = find_complete -->
-			<div class="cont_head">
-				<h3>style24</h3>
-			</div>
-			<div class="cont_body">
-				<div class="form_wrap form_col_c">
-					<div class="form_head">
-						<h4>아이디&#47;비밀번호 찾기</h4>
-					</div>
-					<!-- 아이디찾기 성공일경우 -->
-					<div class="find_result clear">
-						<div class="form_info">
-							<span class="ico_content_find"></span>
-							<p>아이디 찾기 결과 안내</p>
-						</div>
-						<div class="form_print_bar mt40">
-							<ul>
-								<li>
-									<span class="t_span">아이디</span>
-									<span class="c_primary bold" data-font="lato">I***D1</span>
-								</li>
-								<li>
-									<span class="t_span">가입일자</span>
-									<span class="bold" data-font="lato">2020.12.22</span>
-								</li>
-								<li>
-									<span class="t_span">가입경로</span>
-									<span class="bold" data-font="lato">YES24 연동</span>
-								</li>
-							</ul>
-						</div>
-						<div class="btn_group_block btn_group_md ui_row">
-							<div class="ui_col_12">
-								<button class="btn btn_dark btn_block"><span>로그인 하기</span></button>
-							</div>
-						</div>
-					</div>
-					<!-- //아이디찾기 성공일경우 -->
-					<!-- 회원정보로 아이디찾기 실패일경우 -->
-					<div class="find_result clear">
-						<div class="form_info">
-							<span class="ico_content_none"></span>
-							<p>입력한 정보와 일치하는 아이디가 존재하지 않습니다.</p>
-							<p class="t_info mt10">
-								정확한 확인을 위해 휴대폰 인증/아이핀 인증을 통한<br>아이디 찾기를 진행해 주세요.
-							</p>
-						</div>
-						<div class="btn_group_block btn_group_md ui_row">
-							<div class="ui_col_6">
-								<button class="btn btn_primary btn_block"><span>회원가입</span></button>
-							</div>
-							<div class="ui_col_6">
-								<button class="btn btn_dark btn_block"><span>다시 찾기</span></button>
-							</div>
-						</div>
-					</div>
-					<!-- //회원정보로 아이디찾기 실패일경우 -->
-				</div>
-			</div>
-		</div>
-	</div>
-</div>
-
-<script th:inline="javascript">
-/*<![CDATA[*/
-
-/*]]>*/
-</script>
-
-</th:block>
-
-</body>
-</html>

+ 427 - 0
src/main/webapp/WEB-INF/views/web/customer/FindPwdFormWeb.html

@@ -0,0 +1,427 @@
+<!DOCTYPE html>
+<html lang="ko"
+	xmlns:th="http://www.thymeleaf.org"
+	xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
+	layout:decorator="web/common/layout/DefaultLayoutWeb">
+<!--
+ *******************************************************************************
+ * @source  : FindIdFormWeb.html
+ * @desc    : 아이디 비번 찾기 Page
+ *============================================================================
+ * STYLE24
+ * Copyright(C) 2021 TSIT, All rights reserved.
+ *============================================================================
+ * VER  DATE         AUTHOR      DESCRIPTION
+ * ===  ===========  ==========  =============================================
+ * 1.0  2021.02.05   jsshin     최초 작성
+ *******************************************************************************
+ -->
+<body>
+
+<th:block layout:fragment="content">
+<div id="container" class="container mb">
+	<div class="wrap">
+		<div class="content find">
+			<div class="cont_head">
+				<h3>style24</h3>
+			</div>
+			<div class="cont_body">
+				<div class="form_wrap form_col_c" role="form">
+					<div class="form_head">
+						<h4>아이디&#47;비밀번호 찾기</h4>
+					</div>
+					<div class="registration_nav">
+						<ul>
+							<li><a href="javascript:void(0)" onclick="cfnGoToPage(_PAGE_CUSTOMER_ID_FIND);">아이디 찾기</a></li>
+							<li class="active"><a href="javascript:void(0)" onclick="cfnGoToPage(_PAGE_CUSTOMER_PWD_FIND);">비밀번호 찾기</a></li>
+						</ul>
+					</div>
+					<div class="registration_tap">
+						<div class="form_group" style="display: block;">
+							<!-- 비밀번호찾기일경우 -->
+							<div id="searchDiv" class="foldGroup checkcase">
+								<ul>
+									<li>
+										<form id="searchCustInfo" name="searchCustInfo" class="form_wrap" role="form" method="post">
+											<div class="fold_head">
+												<a href="javascript:void(0)">
+													<div>
+														<div class="fold_tit" style="width: inherit;">
+															<span style="width: inherit;">회원정보로 찾기</span>
+														</div>
+													</div>
+												</a>
+											</div>
+											<div class="fold_cont">
+												<div class="txt mb30">
+													<p>등록된 내 회원정보로 찾을 수 있습니다.</p>
+												</div>
+												<div class="form_field form_full">
+													<label class="input_label sr-only">아이디</label>
+													<div class="ui_col_12">
+														<div class="input_wrap">
+															<input type="text" name="custId" placeholder="아이디" class="form_control" maxlength="30"/>
+															<button type="button" id="btnSearchId" class="btn btn_primary">
+																<span>확인</span>
+															</button>
+														</div>
+													</div>
+												</div>
+												<div class="form_field">
+													<label class="input_label sr-only">이름</label>
+													<div class="ui_col_12">
+														<div class="input_wrap">
+															<input type="text" id="custNm" name="custNm" placeholder="이름" class="form_control" maxlength="30"/>
+														</div>
+													</div>
+												</div>
+												<div class="form_field">
+													<label class="input_label sr-only">이메일</label>
+													<div class="ui_col_12">
+														<div class="input_wrap">
+															<input type="text" id="email" name="email" placeholder="이메일" class="form_control" maxlength="30"/>
+														</div>
+													</div>
+												</div>
+												<div class="btn_group_block ui_row mt20">
+													<div class="ui_col_12">
+														<button type="button" id="btnInfoConfirm" class="btn btn_dark btn_block">
+															<span>확인</span>
+														</button>
+													</div>
+												</div>
+											</div>
+										</form>
+									</li>
+									<li>
+										<div class="fold_head">
+											<a href="javascript:void(0)">
+												<div>
+													<div class="fold_tit" style="width: inherit;">
+														<span style="width: inherit;">휴대폰 본인인증으로 찾기</span>
+													</div>
+												</div>
+											</a>
+										</div>
+										<div class="fold_cont">
+											<div class="txt">
+												<p>회원님의 명의로 등록된 휴대폰으로 본인확인을 진행합니다.</p>
+											</div>
+											<div class="ui_row mt20">
+												<div class="ui_col_12">
+													<button type="button" id="btnCellPhoneCertify" class="btn btn_dark btn_block">
+														<span>본인명의 휴대폰으로 인증</span>
+													</button>
+												</div>
+											</div>
+										</div>
+									</li>
+									<li>
+										<div class="fold_head">
+											<a href="javascript:void(0)">
+												<div>
+													<div class="fold_tit" style="width: inherit;">
+														<span style="width: inherit;">아이핀 인증으로 찾기</span>
+													</div>
+												</div>
+											</a>
+										</div>
+										<div class="fold_cont">
+											<div class="txt">
+												<p>아이핀 인증을 통해 찾을 수 있습니다.</p>
+											</div>
+											<div class="ui_row mt20">
+												<div class="ui_col_12">
+													<button type="button" id="btnIpinCertify" class="btn btn_dark btn_block">
+														<span>아이핀 인증</span>
+													</button>
+												</div>
+											</div>
+										</div>
+									</li>
+								</ul>
+							</div>
+							<!-- //비밀번호찾기일경우 -->
+							<!-- 비밀번호 재설정 -->
+							<div id="resetPasswordDiv" class="find_result clear" style="display: none;">
+								<form id="resetPasswordForm" name="resetPasswordForm" method="post">
+									<input type="hidden" name="custId"/>
+									<div class="form_info">
+										<span class="ico_content_security"></span>
+										<p>안전을 위해 비밀번호를 변경하신 후 이용이 가능합니다.</p>
+									</div>
+									<div class="form_field mt40">
+										<label class="input_label sr-only">신규 비밀번호</label>
+										<div class="ui_col_12">
+											<input type="password" id="passwd" name="passwd" placeholder="신규 비밀번호" minlength="8" maxlength="20"/>
+											<!-- case (사용불가 비밀번호일경우,사용가능한 비밀번호일경우) -->
+											<div class="help_block">
+												<!-- 사용불가 비밀번호일경우 -->
+												<p class="mt10">
+													<span id="firstFailed" class="c_black2 hide">
+														<i class="ico ico_check black mr5"></i>영문(대/소문자), 숫자, 특수문자 중 2가지 이상 조합(8~20자) <br/>
+													</span>
+													<span id="secondFailed" class="c_red2 hide">
+														<i class="ico ico_check red mr5"></i>4개이상 연속되거나 동일한 문자/숫자 제외 <br/>
+													</span>
+													<span id="thirdFailed" class="c_gray hide">
+														<i class="ico ico_check gray mr5"></i>아이디 제외
+													</span>
+												</p>
+												<!-- //사용불가 비밀번호일경우 -->
+												<!-- 사용가능한 비밀번호일경우 -->
+												<p id="avlPwd" class="mt10 hide">
+													<span class="c_black2">
+														<i class="ico ico_check black mr5"></i>사용 가능한 비밀번호입니다.
+													</span>
+												</p>
+												<!-- //사용가능한 비밀번호일경우 -->
+											</div>
+											<!-- //case (사용불가 비밀번호일경우,사용가능한 비밀번호일경우) -->
+										</div>
+									</div>
+									<div class="form_field">
+										<label class="input_label sr-only">비밀번호 확인</label>
+										<div class="ui_col_12">
+											<input type="password" id="confirmPassword" name="confirmPassword" placeholder="비밀번호 확인" minlength="8" maxlength="20"/>
+											<!-- case (비밀번호확인 틀렸을경우,비밀번호 일치할경우) -->
+											<div class="help_block">
+												<!-- 비밀번호확인 틀렸을경우 -->
+												<p id="misPwd" class="t_err hide">
+													새 비밀번호가 일치하지 않습니다.
+												</p>
+												<!-- //비밀번호확인 틀렸을경우 -->
+												<!-- 비밀번호 일치할경우 -->
+												<p id="avlConPwd" class="mt10 hide">
+													<span class="c_black2">
+														<i class="ico ico_check black mr5"></i>새 비밀번호가 일치합니다.
+													</span>
+												</p>
+												<!-- //비밀번호 일치할경우 -->
+											</div>
+											<!-- //case (비밀번호확인 틀렸을경우,비밀번호 일치할경우) -->
+										</div>
+									</div>
+									<div class="btn_group_block btn_group_md ui_row">
+										<div class="ui_col_12">
+											<button type="button" id="btnSavePassword" class="btn btn_dark btn_block" disabled="disabled">
+												<span>변경 후 다시 로그인</span>
+											</button>
+										</div>
+									</div>
+								</form>
+							</div>
+							<!-- //비밀번호 재설정 -->
+							<!-- 임시비밀번호 발급 -->
+							<div id="sendEmailDiv" class="find_result clear" style="display: none">
+								<div class="form_info">
+									<span class="ico_content_mail"></span>
+									<p>아래의 이메일로 임시비밀번호가 발급되었습니다.</p>
+									<p class="t_info mt10">
+										로그인 시 비밀번호를 새로 설정하신 후 이용하실 수 있습니다.
+									</p>
+								</div>
+								<div class="form_print_bar mt40">
+									<p id="sendEmail" class="c_primary bold" data-font="lato"></p>
+								</div>
+								<div class="btn_group_block btn_group_md ui_row">
+									<div class="ui_col_12">
+										<button type="button" class="btn btn_dark btn_block" onclick="cfnGoToPage(_PAGE_LOGIN);">
+											<span>로그인 하기</span>
+										</button>
+									</div>
+								</div>
+							</div>
+							<!-- //임시비밀번호 발급 -->
+							<!-- 비밀번호 찾기 결과안내 실패일경우 -->
+							<div id="failAuthentication" class="find_result clear" style="display: none;">
+								<div class="form_info">
+									<span class="ico_content_none"></span>
+									<p>입력한 정보와 일치하는 정보가 존재하지 않습니다.</p>
+									<p class="t_info mt10">
+										<span class="c_primary">STYLE24의 새로운 가족이 되어 주세요!</span>
+									</p>
+								</div>
+								<div class="btn_group_block btn_group_md ui_row">
+									<div class="ui_col_12">
+										<button type="button" class="btn btn_primary btn_block" onclick="cfnGoToPage(_PAGE_CUSTOMER_JOIN);">
+											<span>회원가입</span>
+										</button>
+									</div>
+								</div>
+							</div>
+							<!-- //비밀번호 찾기 결과안내 실패일경우 -->
+						</div>
+					</div>
+				</div>
+			</div>
+		</div>
+	</div>
+</div>
+
+<script th:src="@{'/ux/customer/customer.js?v=' + ${#calendars.format(#calendars.createNow(), 'yyyyMMddHHmmss')}}" src="/ux/customer/customer.js"></script>
+<script th:inline="javascript">
+/*<![CDATA[*/
+	let custIdCheck = false;
+
+	// 아이디 확인
+	$('#btnSearchId').on('click', function () {
+		let custId = $('#searchCustInfo input[name=custId]').val();
+		if(gagajf.isNull(custId)) {
+			mcxDialog.alert("아이디를 입력해주세요.");
+			return;
+		}
+		let custInfo = {};
+		custInfo.custId = custId;
+		let jsonData = JSON.stringify(custInfo);
+		ajaxJsonSubmit('/customer/id/check', jsonData, fnIdConfirmCallBack)
+	});
+
+	var fnIdConfirmCallBack = function (result) {
+		if (result.isFind) {
+			custIdCheck = true;
+		} else {
+			mcxDialog.alert("입력하신 아이디는 STYLE24 회원이 아닙니다. \n 다시 확인해주세요.");
+		}
+	};
+
+	$('#btnInfoConfirm').on('click', function () {
+		let custInfo = $('#searchCustInfo').serializeObject();
+
+		if(gagajf.isNull(custInfo.custId)) {
+			mcxDialog.alert("아이디를 입력해주세요.");
+			return;
+		}
+
+		if (gagajf.isNull(custInfo.custNm)) {
+			mcxDialog.alert('이름을 형식에 맞게 입력해주세요.');
+			return;
+		}
+
+		if (gagajf.isNull(custInfo.email)) {
+			mcxDialog.alert('이메일을 입력하여 주세요.');
+			return;
+		}
+
+		if (!fnCheckValidationEmail(custInfo.email)) {
+			mcxDialog.alert('이메일 형식에 맞게 입력해주세요.');
+			return;
+		}
+		if (!custIdCheck) {
+			mcxDialog.alert('아이디 확인 눌러 주세요.');
+			return;
+		}
+		custInfo.authMethod = 'custInfo';
+		let jsonData = JSON.stringify(custInfo);
+		//console.log('jsonData', jsonData);
+		ajaxJsonSubmit('/customer/pwd/find/custinfo', jsonData, fnInfoConfirmCallBack);
+	});
+
+	// 휴대폰 인증
+	$('#btnCellPhoneCertify').on('click', function () {
+		cfnOpenCellphoneCertify();
+	});
+
+	// 아이핀 인증
+	$('#btnIpinCertify').on('click', function () {
+		cfnOpenIpinCertify();
+	});
+
+	// 찾기결과
+	var fnInfoConfirmCallBack = function (result) {
+		$('.form_head').hide();
+		$('.registration_nav').hide();
+		$('#searchDiv').hide();
+		if (result.isFind) {
+			fnGetDisplaySucc(result.authMethod, result);
+		} else {
+			fnGetDisplayFail(result.authMethod);
+		}
+	};
+
+	// 찾기성공
+	var fnGetDisplaySucc = function (authMethod, custInfo) {
+		if (custInfo.authMethod === 'custInfo') {
+			$('#sendEmail').text(custInfo.maskingEmail)
+			$('#sendEmailDiv').show();
+		}
+		if (authMethod === 'mobile' || authMethod === 'ipin') {
+			$('#resetPasswordForm input[name=custId]').val(custInfo.custId);
+			$('#resetPasswordDiv').show();
+		}
+	};
+
+	// 찾기실패
+	var fnGetDisplayFail = function (authMethod) {
+		$('.form_head').hide();
+		$('.registration_nav').hide();
+		$('#failAuthentication').show();
+	};
+
+	// 나이스 본인인증 후 콜백
+	var fnNiceCallBack = function(encData, authMethod) {
+		if (!gagajf.isNull(encData)) {
+			let custInfo = {};
+			custInfo.encData = encData;
+			custInfo.authMethod = authMethod;
+			let jsonData = JSON.stringify(custInfo);
+			ajaxJsonSubmit('/customer/pwd/find/certify', jsonData, fnInfoConfirmCallBack)
+		}
+	};
+
+	// 패스워드 입력
+	$('#resetPasswordForm input[name=passwd]').on('focus focusout keyup keydown', function () {
+		fnCheckPassword('#resetPasswordForm');
+	});
+
+	// 패스워드 확인 입력
+	$('#resetPasswordForm input[name=confirmPassword]').on('focus focusout keyup keydown', function () {
+		fnConfirmPassword('#resetPasswordForm');
+	});
+
+	// 패스워드 저장
+	$('#btnSavePassword').on('click', function () {
+		let resetPasswordForm = $('#resetPasswordForm').serializeObject();
+
+		if (gagajf.isNull(resetPasswordForm.passwd)) {
+			mcxDialog.alert('신규 비밀번호를 입력하신 후 다시 시도해주세요.');
+			return;
+		}
+
+		if (gagajf.isNull(resetPasswordForm.confirmPassword)) {
+			mcxDialog.alert('비밀번호 확인을 입력하신 후 다시 시도해주세요.');
+			return;
+		}
+
+		if (resetPasswordForm.passwd != resetPasswordForm.confirmPassword) {
+			mcxDialog.alert('비밀번호가 일치하지 않습니다. 다시 확인해주세요.');
+			return;
+		}
+
+		fnCheckPassword('#resetPasswordForm');
+		fnConfirmPassword('#resetPasswordForm');
+		let jsonData = JSON.stringify(resetPasswordForm);
+		ajaxJsonSubmit('/customer/password/reset', jsonData, fnSavePasswordCallback);
+	});
+
+	var fnSavePasswordCallback = function (result) {
+		if (result.isSuccess) {
+		mcxDialog.alertC('비밀번호 변경이 완료 되었습니다.', {
+			sureBtnText: "확인",
+			sureBtnClick: function() {
+				cfnGoToPage(_PAGE_LOGIN);
+			}
+		});
+		} else {
+			mcxDialog.alert('비밀번호 변경이 실패 되었습니다.')
+		}
+	};
+
+
+/*]]>*/
+</script>
+
+</th:block>
+
+</body>
+</html>

+ 0 - 105
src/main/webapp/WEB-INF/views/web/customer/FindPwdResultFormWeb.html

@@ -1,105 +0,0 @@
-<!DOCTYPE html>
-<html lang="ko"
-	xmlns:th="http://www.thymeleaf.org"
-	xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
-	layout:decorator="web/common/layout/DefaultLayoutWeb">
-<!--
- *******************************************************************************
- * @source  : FindIdResultFormWeb.html
- * @desc    : 비밀번호 설정 화면 안내 Page
- *============================================================================
- * STYLE24
- * Copyright(C) 2021 TSIT, All rights reserved.
- *============================================================================
- * VER  DATE         AUTHOR      DESCRIPTION
- * ===  ===========  ==========  =============================================
- * 1.0  2021.02.05   jsshin     최초 작성
- *******************************************************************************
- -->
-<body>
-
-<th:block layout:fragment="content">
-<div id="container" class="container mb">
-	<div class="wrap">
-		<div class="content security_pw"> <!-- 페이지특정 클래스 = security_pw -->
-			<div class="cont_head">
-				<h3>style24</h3>
-			</div>
-			<div class="cont_body">
-				<form class="form_wrap form_col_c form_full" role="form">
-					<div class="form_head">
-						<h4>아이디&#47;비밀번호 찾기</h4>
-					</div>
-					<!-- 비밀번호 재설정 -->
-					<div class="find_result clear">
-						<div class="form_info">
-							<span class="ico_content_security"></span>
-							<p>안전을 위해 비밀번호를 변경하신 후 이용이 가능합니다.</p>
-						</div>
-						<div class="form_field mt40">
-							<label class="input_label sr-only">신규 비밀번호</label>
-							<div class="ui_col_12">
-								<input type="password" name="userPassword" placeholder="신규 비밀번호" id="txtPassword">
-								<!-- case (사용불가 비밀번호일경우,사용가능한 비밀번호일경우) -->
-								<div class="help_block">
-									<!-- 사용불가 비밀번호일경우 -->
-									<p class="mt10">
-										<span class="c_black2"><i class="ico ico_check black mr5"></i>영문(대/소문자), 숫자, 특수문자 중 2가지 이상 조합(8~20자)</span><br>
-										<span class="c_red2"><i class="ico ico_check red mr5"></i>4개이상 연속되거나 동일한 문자/숫자 제외</span><br>
-										<span class="c_gray"><i class="ico ico_check gray mr5"></i>아이디 제외</span>
-									</p>
-									<!-- //사용불가 비밀번호일경우 -->
-									<!-- 사용가능한 비밀번호일경우 -->
-									<p class="mt10">
-										<span class="c_black2"><i class="ico ico_check black mr5"></i>사용 가능한 비밀번호입니다</span>
-									</p>
-									<!-- //사용가능한 비밀번호일경우 -->
-								</div>
-								<!-- //case (사용불가 비밀번호일경우,사용가능한 비밀번호일경우) -->
-							</div>
-						</div>
-						<div class="form_field">
-							<label class="input_label sr-only">비밀번호 확인</label>
-							<div class="ui_col_12">
-								<input type="password" name="userConfirm" placeholder="비밀번호 확인" id="txtConfirm">
-								<!-- case (비밀번호확인 틀렸을경우,비밀번호 일치할경우) -->
-								<div class="help_block">
-									<!-- 비밀번호확인 틀렸을경우 -->
-									<p class="t_err">
-										새 비밀번호가 일치하지 않습니다.
-									</p>
-									<!-- //비밀번호확인 틀렸을경우 -->
-									<!-- 비밀번호 일치할경우 -->
-									<p class="mt10">
-										<span class="c_black2">
-											<i class="ico ico_check black mr5"></i>새 비밀번호가 일치합니다.
-										</span>
-									</p>
-									<!-- //비밀번호 일치할경우 -->
-								</div>
-								<!-- //case (비밀번호확인 틀렸을경우,비밀번호 일치할경우) -->
-							</div>
-						</div>
-						<div class="btn_group_block btn_group_md ui_row">
-							<div class="ui_col_12">
-								<button class="btn btn_dark btn_block"><span>변경 후 다시 로그인</span></button>
-							</div>
-						</div>
-					</div>
-					<!-- //비밀번호 재설정 -->
-				</form>
-			</div>
-		</div>
-	</div>
-</div>
-
-<script th:inline="javascript">
-/*<![CDATA[*/
-
-/*]]>*/
-</script>
-
-</th:block>
-
-</body>
-</html>

+ 30 - 0
src/main/webapp/WEB-INF/views/web/customer/NiceCallbackFormWeb.html

@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html lang="ko"
+	  xmlns:th="http://www.thymeleaf.org">
+<!--
+ *******************************************************************************
+ * @source  : NiceCallbackFormWeb.html
+ * @desc    : NICE 인증콜백 Page
+ *============================================================================
+ * STYLE24
+ * Copyright(C) 2021 TSIT, All rights reserved.
+ *============================================================================
+ * VER  DATE         AUTHOR      DESCRIPTION
+ * ===  ===========  ==========  =============================================
+ * 1.0  2021.02.09   jsshin     최초 작성
+ *******************************************************************************
+ -->
+<body>
+
+<script th:inline="javascript">
+	/*<![CDATA[*/
+	window.onload = function () {
+		top.opener.fnNiceCallBack([[${sEncData}]], [[${authMethod}]]);
+		self.close();
+	}
+
+	/*]]>*/
+</script>
+
+</body>
+</html>

+ 37 - 0
src/main/webapp/WEB-INF/views/web/customer/NiceCellPhoneFormWeb.html

@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<html lang="ko"
+	  xmlns:th="http://www.thymeleaf.org">
+<!--
+ *******************************************************************************
+ * @source  : NiceCellPhoneFormWeb.html
+ * @desc    : NICE 휴대폰 인증 Page
+ *============================================================================
+ * STYLE24
+ * Copyright(C) 2021 TSIT, All rights reserved.
+ *============================================================================
+ * VER  DATE         AUTHOR      DESCRIPTION
+ * ===  ===========  ==========  =============================================
+ * 1.0  2021.02.09   jsshin     최초 작성
+ *******************************************************************************
+ -->
+<body>
+
+<form name="niceAuthForm" id="niceAuthForm" method="post" >
+	<input type="hidden" name="m" value="checkplusSerivce" />
+	<input type="hidden" name="EncodeData" th:value="${sEncData}" />
+</form>
+
+<script th:inline="javascript">
+	/*<![CDATA[*/
+
+	window.onload = function () {
+		document.niceAuthForm.action="https://nice.checkplus.co.kr/CheckPlusSafeModel/checkplus.cb";
+		document.niceAuthForm.target="popupCellphone";
+		document.niceAuthForm.submit();
+	};
+	/*]]>*/
+</script>
+
+
+</body>
+</html>

+ 39 - 0
src/main/webapp/WEB-INF/views/web/customer/NiceIpinFormWeb.html

@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<html lang="ko"
+	  xmlns:th="http://www.thymeleaf.org">
+<!--
+ *******************************************************************************
+ * @source  : NiceIpinFormWeb.html
+ * @desc    : NICE 아이핀 인증 Page
+ *============================================================================
+ * STYLE24
+ * Copyright(C) 2021 TSIT, All rights reserved.
+ *============================================================================
+ * VER  DATE         AUTHOR      DESCRIPTION
+ * ===  ===========  ==========  =============================================
+ * 1.0  2021.02.09   jsshin     최초 작성
+ *******************************************************************************
+ -->
+<!--<head th:replace="~{web/common/fragments/HeaderWeb :: header}"></head>-->
+<!--<th:block th:replace="~{web/common/fragments/VariablesWeb :: variables}"></th:block>-->
+<body>
+
+<form name="niceAuthForm" id="niceAuthForm" method="post" >
+	<input type="hidden" name="m" value="pubmain" />
+	<input type="hidden" name="enc_data" th:value="${sEncData}" />
+</form>
+
+<script th:inline="javascript">
+	/*<![CDATA[*/
+
+	window.onload = function () {
+		document.niceAuthForm.action="https://cert.vno.co.kr/ipin.cb";
+		document.niceAuthForm.target="popupIpin";
+		document.niceAuthForm.submit();
+	};
+	/*]]>*/
+</script>
+
+
+</body>
+</html>

+ 335 - 0
src/main/webapp/WEB-INF/views/web/mypage/MypageOrderDetailFormWeb.html

@@ -0,0 +1,335 @@
+<!DOCTYPE html>
+<html lang="ko"
+	xmlns:th="http://www.thymeleaf.org"
+	xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
+	layout:decorator="web/common/layout/MypageLayoutWeb">
+<!--
+ *******************************************************************************
+ * @source  : MypageOrderDetailFormWeb.html
+ * @desc    : 마이페이지 > 주문상세 Page
+ *============================================================================
+ * STYLE24
+ * Copyright(C) 2021 TSIT, All rights reserved.
+ *============================================================================
+ * VER  DATE         AUTHOR      DESCRIPTION
+ * ===  ===========  ==========  =============================================
+ * 1.0  2021.02.16   card007     최초 작성
+ *******************************************************************************
+ -->
+<body>
+
+<th:block layout:fragment="content">
+	<div class="my_cont">
+		<div class="sec_head">
+			<h3>주문상세</h3>
+			<div class="od_detail">
+				(주문번호 : <span class="num" th:text="${ordNo}"></span>)
+			</div>
+			<button type="button" class="btn btn_default od_del_btn"><span>주문 내역 삭제</span></button>
+		</div>
+		<div class="sec_body">
+			<div class="order_list">
+				<section class="order_row">
+					<th:block th:if="${orderList}" th:each="oneData, status : ${orderList}">
+						<div class="part_deliver">
+							<div class="tbl_tit">
+								<!-- 주문일/선물일 설정 -->
+								<span class="start_t" th:unless="${oneData.giftPackYn == 'Y'}">주문일</span>
+								<span class="gift_t" th:if="${oneData.giftPackYn == 'Y'}">선물일</span>
+								<!-- //주문일/선물일 설정 -->
+								<span class="order_date" th:text="${oneData.ordDt}"></span>
+								<span class="order_label01" th:if="${oneData.selfGoodsYn == 'N'}">업체직배송</span>
+								<span class="order_label01" th:if="${oneData.shotDelvYn == 'N' and oneData.selfGoodsYn == 'Y'}">STYLE24 일반배송</span>
+								<span class="order_label02" th:if="${oneData.shotDelvYn == 'Y'}">총알배송</span>
+								<a href="" class="detail_btn">주문상세보기</a>
+							</div>
+							<th:block th:if="${oneData.orderList}" th:each="order, status : ${oneData.orderList}" th:with="imageUrl=${@environment.getProperty('upload.goods.view')}">
+								<div class="tbl type2">
+									<table>
+										<colgroup>
+											<col width="1020">
+											<col width="180">
+										</colgroup>
+										<tbody>
+											<tr class="bundle_row">
+												<td>
+													<div class="info_item">
+														<div class="thumb_box">
+															<a href="">
+																<img th:src="${imageUrl + '/' + order.sysImgNm}" width="100%" alt="">
+															</a>
+														</div>
+														<div class="info_box">
+															<p class="od_name">
+																<a href="">
+																	<span class="brand" th:text="${order.brandNm}"></span>
+																	<span class="name" th:text="${order.goodsNm}"></span>
+																</a>
+															</p>
+															<p class="od_opt">
+																<span class="option"><em th:text="${order.optCd1}"></em><em th:text="${order.optCd2}"></em></span>
+																<span class="count">수량 <em th:text="${order.ordQty}"></em>개</span>
+															</p>
+															<button type="button" class="btn btn_dark cart_btn">쇼핑백 담기</button>
+														</div>
+														<div class="info_calc">
+															<p class="price">
+																<span class="selling_price" th:text="|${#numbers.formatInteger(order.ordAmt, 1, 'COMMA')}원|"></span>
+															</p>
+															<p class="point"><span th:text="${#numbers.formatInteger(order.savePntAmt, 1, 'COMMA')}"></span>p</p>
+														</div>
+													</div>
+												</td>
+												<td class="merge_row"> <!-- 같은 데이터 노출시 동일 영역끼리 병합 : 클래스명 merge_row 추가 -->
+													<div class="delivery">
+														<p class="dlvr_staus" th:text="${order.ordDtlStatNm}"></p>
+														<p class="dlvr_desc" th:if="${order.delvEddt}" th:text="|${order.delvEddt}일 도착|"></p>
+													</div>
+													<div class="tbl_btn_wrap case02">
+														<button type="button" class="btn btn_default btn_sm"><span>교환</span></button>
+														<button type="button" class="btn btn_default btn_sm"><span>반품/취소</span></button>
+														<button type="button" class="btn btn_default btn_sm" th:if="${order.reviewSq == 0}"><span>리뷰작성</span></button>
+													</div>
+												</td>
+											</tr>
+										</tbody>
+									</table>
+								</div>
+								<div class="order_confirm">
+									<p class="cf_txt cf_desc c_primary" th:if="${order.ordDtlStat == 'G013_00' or order.ordDtlStat == 'G013_10' or order.ordDtlStat == 'G013_11'}">주문 완료 / 결제를 기다리고 있습니다.</p> <!-- button 없이 텍스트만 있을 경우 cf_desc c_primary class 추가 -->
+									<p class="cf_txt cf_desc c_primary" th:if="${order.ordDtlStat == 'G013_20' or order.ordDtlStat == 'G013_30' or order.ordDtlStat == 'G013_35'}">배송할 상품을 준비 중입니다.</p>
+									<p class="cf_txt cf_desc c_primary" th:if="${order.ordDtlStat == 'G013_40'}">상품준비가 완료되어 곧 배송될 예정입니다.</p>
+									<p class="cf_txt cf_desc c_primary" th:if="${order.ordDtlStat == 'G013_50' or order.ordDtlStat == 'G013_55'}" th:text="|${order.shipCompNm} / ${order.invoiceNo}|"></p>
+									<button type="button" class="btn btn_primary" th:if="${order.ordDtlStat == 'G013_50' or order.ordDtlStat == 'G013_55'}">배송조회</button>
+									<p class="cf_txt cf_desc c_primary" th:if="${order.ordDtlStat == 'G013_60'}" th:text="|${order.purchaseConfirmDay}일 후 자동으로 구매확정|"></p>
+									<button type="button" class="btn btn_primary" th:if="${order.ordDtlStat == 'G013_60'}">구매확정 하기</button>
+									<p class="cf_txt cf_desc c_primary" th:if="${order.ordDtlStat == 'G013_70' and order.reviewSq == 0}">리뷰를 작성하면 다른 구매자에게 도움이 될 수 있습니다.</p>
+									<button type="button" class="btn btn_primary" th:if="${order.ordDtlStat == 'G013_70' and order.reviewSq == 0}">리뷰작성</button>
+									<p class="cf_txt cf_desc c_primary" th:if="${order.ordDtlStat == 'G013_70' and order.reviewSq > 0}">주문내역 다시 구매하기 위해</p>
+									<button type="button" class="btn btn_primary" th:if="${order.ordDtlStat == 'G013_70' and order.reviewSq > 0}">장바구니 담기</button>
+								</div>
+							</th:block>
+						</div>
+					</th:block>
+				</section>
+				<section class="order_row" th:if="${paymentInfo.payMeans == 'G014_20'}">
+					<div class="order_tit">
+						<h3 class="subH3">무통장 입금 정보</h3>
+					</div>
+					<div class="tbl type1 row_tbl">
+						<table>
+							<colgroup>
+								<col width="*">
+							</colgroup>
+							<tbody>
+								<tr>
+									<td>
+										<div>
+											<span th:text="${paymentInfo.vaBank}"></span>(<span th:text="${paymentInfo.vaNm}"></span>)
+										</div>
+										<div>
+											<span th:text="${paymentInfo.vaNo}"></span>
+										</div>
+										<div>
+											<span th:text="${paymentInfo.vaDeadlineYmd}"></span><span th:text="${paymentInfo.vaDeadlineHms}"></span> 까지
+										</div>
+									</td>
+								</tr>
+							</tbody>
+						</table>
+					</div>
+				</section>
+				<section class="order_row">
+					<div class="order_tit">
+						<h3 class="subH3">주문 고객</h3>
+					</div>
+					<div class="tbl type1 row_tbl">
+						<table>
+							<colgroup>
+								<col width="*">
+							</colgroup>
+							<tbody>
+								<tr>
+									<td>
+										<div>
+											<span th:text="${orderInfo.ordNm}"></span>
+										</div>
+										<div>
+											<span th:text="${orderInfo.ordEmail}"></span>
+										</div>
+										<div>
+											<span th:text="${orderInfo.ordPhnno}"></span>
+										</div>
+									</td>
+								</tr>
+							</tbody>
+						</table>
+					</div>
+				</section>
+				<section class="order_row">
+					<div class="order_tit">
+						<h3 class="subH3">배송지 정보</h3>
+					</div>
+					<div class="tbl type1 row_tbl">
+						<table>
+							<colgroup>
+								<col width="*">
+							</colgroup>
+							<tbody>
+							<tr>
+								<td th:text="${deliveryAddrInfo.recipNm}"><span class="sr-only">배송지명</span></td>
+							</tr>
+							<tr>
+								<td th:text="|${deliveryAddrInfo.recipBaseAddr} ${deliveryAddrInfo.recipDtlAddr}|"><span class="sr-only">배송 주소</span></td>
+							</tr>
+							<tr>
+								<td th:text="${deliveryAddrInfo.recipPhnno}"><span class="sr-only">휴대폰 번호</span></td>
+							</tr>
+							<tr>
+								<td th:text="${deliveryAddrInfo.delvMemo}">
+									<span class="tit c_primary">배송요청 사항</span>
+									<button type="button" class="btn_popup" id="btn_rqstModify_pop"><span>변경하기</span></button>
+								</td>
+							</tr>
+							</tbody>
+						</table>
+					</div>
+				</section>
+				<section class="order_row">
+					<div class="order_tit">
+						<h3 class="subH3">결제정보</h3>
+					</div>
+					<div class="order_amount">
+						<div class="tbl type3">
+							<table>
+								<colgroup>
+									<col width="33.33%">
+									<col width="33.33%">
+									<col width="*">
+								</colgroup>
+								<thead>
+								<tr>
+									<th>
+										<dl>
+											<dt>총 주문금액</dt>
+											<dd class="price" th:text="|${#numbers.formatInteger(orderAmtInfo.ordAmt + orderAmtInfo.delvFee, 1, 'COMMA')}원|"></dd>
+										</dl>
+										<i class="ico_calc minus"></i>
+									</th>
+									<th>
+										<dl>
+											<dt>총 할인금액</dt>
+											<dd class="price" th:text="|- ${#numbers.formatInteger(orderAmtInfo.totalDcAmt, 1, 'COMMA')}원|"></dd>
+										</dl>
+										<i class="ico_calc result"></i>
+									</th>
+									<th>
+										<dl>
+											<dt>결제금액</dt>
+											<dd class="price" data-weight="price" data-font="lato">
+												<span class="oder_total_price" th:text="${#numbers.formatInteger(orderAmtInfo.realOrdAmt, 1, 'COMMA')}"></span>원
+											</dd>
+										</dl>
+									</th>
+								</tr>
+								</thead>
+								<tbody>
+								<tr>
+									<td>
+										<dl>
+											<div>
+												<dt>상품금액</dt>
+												<dd th:text="|${#numbers.formatInteger(orderAmtInfo.ordAmt, 1, 'COMMA')}원|"></dd>
+											</div>
+											<div th:if="${orderAmtInfo.delvFee > 0}">
+												<dt>배송비</dt>
+												<dd th:text="|${#numbers.formatInteger(orderAmtInfo.delvFee, 1, 'COMMA')}원|"></dd>
+											</div>
+										</dl>
+									</td>
+									<td>
+										<dl>
+											<div th:if="${orderAmtInfo.cpn1DcAmt > 0}">
+												<dt>상품 할인(즉시 할인)</dt>
+												<dd th:text="|- ${#numbers.formatInteger(orderAmtInfo.cpn1DcAmt, 1, 'COMMA')}원|"></dd>
+											</div>
+											<div th:if="${orderAmtInfo.tmtb1DcAmt + orderAmtInfo.tmtb2DcAmt > 0}">
+												<dt>다다익선 할인</dt>
+												<dd th:text="|- ${#numbers.formatInteger(orderAmtInfo.tmtb1DcAmt + orderAmtInfo.tmtb2DcAmt, 1, 'COMMA')}원|"></dd>
+											</div>
+											<div th:if="${orderAmtInfo.cartCpnDcAmt + orderAmtInfo.goodsCpnDcAmt > 0}">
+												<dt>쿠폰 할인</dt>
+												<dd th:text="|- ${#numbers.formatInteger(orderAmtInfo.cartCpnDcAmt + orderAmtInfo.goodsCpnDcAmt, 1, 'COMMA')}원|">- 30,000원</dd>
+											</div>
+											<div th:if="${orderAmtInfo.prePntDcAmt > 0}">
+												<dt>선 포인트 할인</dt>
+												<dd th:text="|- ${#numbers.formatInteger(orderAmtInfo.prePntDcAmt, 1, 'COMMA')}원|"></dd>
+											</div>
+											<div th:if="${orderAmtInfo.pntDcAmt > 0}">
+												<dt>포인트 사용</dt>
+												<dd th:text="|- ${#numbers.formatInteger(orderAmtInfo.pntDcAmt, 1, 'COMMA')}원|"></dd>
+											</div>
+											<div th:if="${orderAmtInfo.gfcdUseAmt > 0}">
+												<dt>상품권 사용</dt>
+												<dd th:text="|- ${#numbers.formatInteger(orderAmtInfo.gfcdUseAmt, 1, 'COMMA')}원|"></dd>
+											</div>
+											<!-- 
+											<div th:if="${}">
+												<dt>마일리지 사용</dt>
+												<dd></dd>
+											</div>
+											<div th:if="${}">
+												<dt>제휴 할인</dt>
+												<dd></dd>
+											</div>
+											-->
+										</dl>
+									</td>
+									<td>
+										<dl>
+											<div th:if="${orderAmtInfo.savePntAmt > 0}">
+												<dt>적립 예정 포인트</dt>
+												<dd th:text="|${#numbers.formatInteger(orderAmtInfo.savePntAmt, 1, 'COMMA')}P|"></dd>
+											</div>
+											<div>
+												<dt>결제방법</dt>
+												<dd>
+													<span class="paymethod">현대카드/무이자6개월</span>
+												</dd>
+											</div>
+											<!-- 무통장 결제시 -->
+											<div th:if="${paymentInfo.payMeans == 'G014_20'}">
+												<dt>&nbsp;</dt>
+												<dd>
+													<button type="button" class="btn btn_default"><span>신용카드 전표 (현금 영수증)</span></button>
+												</dd>
+											</div>
+											<!-- //무통장 결제시 -->
+										</dl>
+									</td>
+								</tr>
+								</tbody>
+							</table>
+						</div>
+					</div>
+				</section>
+			</div>
+		</div>
+	</div>
+<script src="/ux/plugins/gaga/gaga.paging.js"></script>
+<script th:inline="javascript">
+/*<![CDATA[*/
+	$(document).ready(function() {
+		// 마이페이지 LNB 설정
+		fnSetMypageLnbList(1);
+		
+		// 마이페이지 location 설정
+		fnSetMypageLocation('주문확인/배송조회', _PAGE_ORDER_LIST, '주문상세');
+	});
+/*]]>*/
+</script>
+
+</th:block>
+
+</body>
+</html>

+ 12 - 82
src/main/webapp/WEB-INF/views/web/mypage/MypageOrderListFormWeb.html

@@ -86,12 +86,6 @@
 			<div class="order_sch_filter clear">
 				<div class="sch_radio_tab">
 					<button type="button" class="btn btn_default" th:if="${searchPeriod}" th:each="oneData, status : ${searchPeriod}" th:text="${oneData}"></button>
-<!--					<button type="button" class="btn btn_default">6월</button>-->
-<!--					<button type="button" class="btn btn_default">7월</button>-->
-<!--					<button type="button" class="btn btn_default">8월</button>-->
-<!--					<button type="button" class="btn btn_default">9월</button>-->
-<!--					<button type="button" class="btn btn_default">10월</button>-->
-<!--					<button type="button" class="btn btn_default">11월</button>-->
 				</div>
 				<div class="sch_right">
 					<div class="sch_datepicker sb">
@@ -120,7 +114,7 @@
 							<span class="order_method" th:if="${oneData.shotDelvYn == 'N' and oneData.selfGoodsYn == 'Y'}" th:text="일반배송"></span>
 							<span class="order_method" th:if="${oneData.selfGoodsYn == 'N'}" th:text="업체직배송"></span>
 							<!-- //배송구분 설정 -->
-							<a href="" class="detail_btn">주문상세보기</a>
+							<a href="javascript:void(0)" class="detail_btn" th:attr="ordNo=${oneData.ordNo}" onclick="fnGoToOrderDetail(this)">주문상세보기</a>
 						</div>
 						<div class="tbl type2">
 							<table>
@@ -130,13 +124,13 @@
 									<col width="*">
 								</colgroup>
 								<tbody>
-									<th:block th:if="${oneData.orderList}" th:each="order, status : ${oneData.orderList}">
+									<th:block th:if="${oneData.orderList}" th:each="order, status : ${oneData.orderList}" th:with="imageUrl=${@environment.getProperty('upload.goods.view')}">
 										<tr>
 											<td class="">
 												<div class="info_item">
 													<div class="thumb_box">
 														<a href="">
-															<img src="../ux/images/thumb/tmp_pdClickother1.jpg" width="100%" alt="">
+															<img th:src="${imageUrl + '/' + order.sysImgNm}" width="100%" alt="">
 														</a>
 													</div>
 													<div class="info_box">
@@ -172,13 +166,13 @@
 													<th:block th:if="${oneData.giftPackYn == 'Y'}">
 														<!-- 주소 입력 전 -->
 														<th:block th:if="${#strings.isEmpty(order.recipBaseAddr)}">
-															<p class="dlvr_staus c_primary" th:text="주소 입력 대기"></p>
+															<p class="dlvr_staus c_primary" th:text="|주소 입력 대기|"></p>
 															<p class="dlvr_desc" th:text="|남은 기간 ${order.giftLimitDay}일|"></p>
 															<p class="dlvr_desc" th:text="|(${order.giftLimitDt}까지)|"></p>
 														</th:block>
 														<!-- 주소 입력 후 -->
 														<th:block th:unless="${#strings.isEmpty(order.recipBaseAddr)}">
-															<p class="dlvr_staus c_primary" th:text="선물 완료"></p>
+															<p class="dlvr_staus c_primary" th:text="|선물 완료|"></p>
 															<p class="dlvr_desc" th:text="|(${order.giftCompleteDt})|"></p>
 														</th:block>
 													</th:block>
@@ -210,10 +204,6 @@
 											<th:block th:unless="${oneData.giftPackYn == 'Y'}">
 												<tr>
 													<td colspan="4">
-														<div class="order_confirm" th:if="${order.ordDtlStat == 'G013_00'}">
-															<span class="cf_txt">주문 완료 / 결제를 기다리고 있습니다.</span>
-															<button type="button" class="btn btn_primary">구매확정</button>
-														</div>
 														<div class="order_confirm" th:if="${order.ordDtlStat == 'G013_00' or order.ordDtlStat == 'G013_10' or order.ordDtlStat == 'G013_11'}">
 															<span class="cf_txt">주문 완료 / 결제를 기다리고 있습니다.</span>
 														</div>
@@ -254,7 +244,7 @@
 															<span class="cf_txt" th:text="|${order.recipNm}님께 선물이 발송되었습니다.|"></span>
 														</div>
 														<div class="order_confirm" th:if="${#strings.isEmpty(order.recipBaseAddr) and order.giftLimitDay < 0}">
-															<span class="cf_txt" th:text="주소입력 기한이 경과되어 선물이 취소 되었습니다."></span>
+															<span class="cf_txt" th:text="|주소입력 기한이 경과되어 선물이 취소 되었습니다.|"></span>
 														</div>
 													</td>
 												</tr>
@@ -271,72 +261,6 @@
 				<th:block th:unless="${orderInfo}" th:each="oneData, status : ${orderInfo}">
 
 				</th:block>
-				<!-- 주소 입력 대기 -->
-				<div class="part_deliver">
-					<div class="tbl_tit">
-						<span class="start_t">주문일</span>
-						<!-- 선물일 -->
-						<!-- <span class="gift_t">선물일</span> -->
-						<span class="order_date">2020.10.25</span>
-						<span class="order_method">업체직배송</span>
-						<a href="" class="detail_btn">주문상세보기</a>
-					</div>
-					<div class="tbl type2">
-						<table>
-							<colgroup>
-								<col width="840">
-								<col width="180">
-								<col width="*">
-							</colgroup>
-							<tbody>
-							<tr>
-								<td>
-									<div class="info_item">
-										<div class="thumb_box">
-											<a href="">
-												<img src="/images/pc/thumb/tmp_pdClickother1.jpg" width="100%" alt="">
-											</a>
-										</div>
-										<div class="info_box">
-											<p class="od_name">
-												<a href="">
-													<span class="brand">Mollimelli 몰리멜리</span>
-													<span class="name">몰리겨울상하복 균일가 택1 유아동/상하복/기모상하복/상하의세트 몰리겨울상하복 균일가 택1 유아동/상하복/기모상하복/상하의세트몰리겨울상하복 균일가 택1 유아동/상하복/기모상하복/상하의세트</span>
-												</a>
-											</p>
-											<p class="od_opt">
-												<span class="option">옵션:<em>01_루돌프융기모상하복_D오렌지/110</em></span>
-												<span class="count">수량:<em>99</em>개</span>
-											</p>
-										</div>
-										<div class="info_calc">
-											<p class="price">
-												<span class="selling_price">61,200원</span>
-											</p>
-											<p class="point"><span>49</span>p</p>
-										</div>
-									</div>
-								</td>
-								<td>
-									<div class="delivery">
-										<p class="dlvr_staus c_primary">주소 입력 대기</p>
-										<p class="dlvr_desc">남은 기간 3일</p>
-										<p class="dlvr_desc">(2020.10.05까지)</p>
-									</div>
-								</td>
-								<td>
-									<div class="tbl_btn_wrap case02">
-										<ul>
-											<li><button type="button" id="sms" class="btn btn_dark btn_sm"><span>SMS 재전송</span></button></li>
-										</ul>
-									</div>
-								</td>
-							</tr>
-							</tbody>
-						</table>
-					</div>
-				</div>
-				<!-- //주소 입력 대기 -->
 			</div>
 		</div>
 	</div>
@@ -351,6 +275,12 @@
 		fnSetMypageLocation('주문확인/배송조회');
 	});
 	
+	var fnGoToOrderDetail = function(param) {
+		let ordNo = $(param).attr('ordNo');
+		console.log(_PAGE_ORDER_DETAIL + '/' + ordNo);
+		cfnGoToPage(_PAGE_ORDER_DETAIL + '/' + ordNo);
+	}
+	
 /*]]>*/
 </script>
 

+ 219 - 0
src/main/webapp/ux/customer/customer.js

@@ -0,0 +1,219 @@
+/**
+ *******************************************************************************
+ * @source  : customer.js
+ * @desc    : 회원(고객) 공통 JS
+ *============================================================================
+ * STYLE24
+ * Copyright(C) 2021 TSIT, All rights reserved.
+ *============================================================================
+ * VER  DATE         AUTHOR      DESCRIPTION
+ * ===  ===========  ==========  =============================================
+ * 1.0  2021.02.15   jsshin     최초 작성
+ *******************************************************************************
+ */
+
+
+/**
+ * 이메일 유효성 체크
+ * @param email - 이메일
+ * @return boolean - 통과(true)/실패(fail)
+ * @author jsshin
+ * @since 2021. 02. 15
+ */
+var fnCheckValidationEmail = function (email) {
+	const regexp = /^([\w-]+(?:\.[\w-]+)*)@((?:[\w-]+\.)*\w[\w-]{0,66})\.([a-z]{2,6}(?:\.[a-z]{2})?)$/;
+	let result = true;
+	if (!regexp.test(email)) {
+		result = false;
+	}
+	return result;
+};
+
+/**
+ * 날짜 변환 YYYYMMDD -> YYYY.MM.DD
+ * @param date - 날짜
+ * @return string - YYYY.MM.DD
+ * @author jsshin
+ * @since 2021. 02. 15
+ */
+var fnToDateFormat =  function(date) {
+	if (gagajf.isNull(date))
+		return "";
+	return date.replaceAll("/", "").replaceAll("-", "").toDate("YYYYMMDD").format("YYYY.MM.DD");
+};
+
+/**
+ * 비밀번호 유효성 체크
+ * input name이 custId, password, confirmpassword  동일해야 이 매소드를 사용 할수 있음
+ * 실패 텍스트는 아래에 있는 id 값으로 해야함
+ * @param form 넘김
+ * @author jsshin
+ * @since 2021. 02. 16
+ */
+var fnCheckPassword = function (form) {
+	let custId = $(form + ' input[name=custId]').val();
+	let password = $(form  +' input[name=passwd]').val();
+	let confirmPassword = $(form  + ' input[name=confirmPassword]').val();
+	let $firstFailed = $('#firstFailed');
+	let $secondFailed = $('#secondFailed');
+	let $thirdFailed = $('#thirdFailed');
+	let $avlPwd = $('#avlPwd');
+	let pwdCheck = true;
+
+	// 길이
+	if(!/^[a-zA-Z0-9!@#$%^&*()?_~]{8,20}$/.test(password)) {
+		pwdCheck = false;
+		$firstFailed.show();
+	} else {
+		$firstFailed.hide();
+	}
+
+	// 영문, 숫자, 특수문자 2종 이상 혼용
+	let count = 0;
+	if(password.search(/[0-9]/g) != -1 ) count ++;
+	if(password.search(/[a-zA-Z]/ig)  != -1 ) count ++;
+	if(password.search(/[!@#$%^&*()?_~]/g)  != -1  ) count ++;
+	if(count < 2) {
+		pwdCheck = false;
+		$firstFailed.show();
+	} else {
+		$firstFailed.hide();
+	}
+
+	// 동일한 문자/숫자 4이상, 연속된 문자
+	if(/(\w)\1\1\1/.test(password) || isContinuedValue(password)) {
+		pwdCheck = false;
+		$secondFailed.show();
+	} else {
+		$secondFailed.hide();
+	}
+
+	// 아이디 포함 여부
+	if(password.search(custId) > -1) {
+		pwdCheck = false;
+		$thirdFailed.show();
+	} else {
+		$thirdFailed.hide();
+	}
+
+	// 사용 가능한 비밀번호인지
+	if (pwdCheck) {
+		$avlPwd.show();
+	} else {
+		$avlPwd.hide();
+	}
+
+	if (!gagajf.isNull(confirmPassword)) {
+		fnConfirmPassword(form);
+	}
+
+};
+
+/**
+ * 확인 비밀번호 유효성 체크
+ * input name이 custId, password, confirmpassword  동일해야 이 매소드를 사용 할수 있음
+ * 실패 텍스트는 아래에 있는 id 값으로 해야함
+ * @param form 넘김
+ * @author jsshin
+ * @since 2021. 02. 16
+ */
+var fnConfirmPassword = function (form) {
+	let password = $(form  +' input[name=passwd]').val();
+	let confirmPassword = $(form  + ' input[name=confirmPassword]').val();
+	let $misPwd = $('#misPwd');
+	let $avlConPwd = $('#avlConPwd');
+	let $btnSavePassword = $('#btnSavePassword');
+
+	// 재입력 일치 여부
+	if (password != confirmPassword) {
+		$avlConPwd.hide();
+		$misPwd.show();
+		$btnSavePassword.attr('disabled', true);
+	} else {
+		$misPwd.hide();
+		$avlConPwd.show();
+		$btnSavePassword.attr('disabled', false);
+	}
+}
+
+/**
+ * 연속되는 문자가 있는지 확인
+ * @param form 넘김
+ * @return true/false
+ * @author jsshin
+ * @since 2021. 02. 16
+ */
+var isContinuedValue = function (password) {
+	var intCnt1 = 0;
+	var intCnt2 = 0;
+	var temp0 = "";
+	var temp1 = "";
+	var temp2 = "";
+	var temp3 = "";
+
+	for (var i = 0; i < password.length-3; i++) {
+		temp0 = password.charAt(i);
+		temp1 = password.charAt(i + 1);
+		temp2 = password.charAt(i + 2);
+		temp3 = password.charAt(i + 3);
+
+		if (temp0.charCodeAt(0) - temp1.charCodeAt(0) == 1
+			&& temp1.charCodeAt(0) - temp2.charCodeAt(0) == 1
+			&& temp2.charCodeAt(0) - temp3.charCodeAt(0) == 1) {
+			intCnt1 = intCnt1 + 1;
+		}
+
+		if (temp0.charCodeAt(0) - temp1.charCodeAt(0) == -1
+			&& temp1.charCodeAt(0) - temp2.charCodeAt(0) == -1
+			&& temp2.charCodeAt(0) - temp3.charCodeAt(0) == -1) {
+			intCnt2 = intCnt2 + 1;
+		}
+
+	}
+	return (intCnt1 > 0 || intCnt2 > 0);
+}
+
+
+/*
+* 임시사용
+*
+* */
+var ajaxJsonSubmit = function (url, json, callback) {
+	$.ajax({
+		type : "POST",
+		url : url,
+		dataType : 'json',
+		data : json,
+		beforeSend : function(xhr, opts) { // 통신 전
+			// when validation is false
+			// AJAX call
+			xhr.setRequestHeader('AJAX', 'true');
+			// dataType: "json"일 때
+			xhr.setRequestHeader('Accept', 'application/json');
+			xhr.setRequestHeader('Content-Type', 'application/json');
+		},
+		success : function(result) {
+			if (typeof(result.status) == 'undefined' || result.status === 200) { // 성공
+				if (!gagajf.isNull(result.message)) {
+					if (mcxDialog.alert(result.message)) {
+						if (typeof(callback) === 'function') {
+							callback.call(this, result);
+						}
+					}
+				} else {
+					if (typeof(callback) == "function") {
+						callback.call(this, result);
+					}
+				}
+			} else { // 실패
+				if (!gagajf.isNull(result.error.message)) {
+					mcxDialog(result.error.message);
+				}
+			}
+		},
+		error : function() {
+			// error code
+			mcxDialog.alert('오류로 인해 처리되지 않았습니다.');
+		}
+	});
+}

+ 1 - 1
src/main/webapp/ux/plugins/gaga/gaga.validation.js

@@ -9,7 +9,7 @@
  *
  * Using)
  * 		1. Add "data-valid-type" and "data-valid-name" attribute to Elements of form
- * 			ex) <input type="text" name="userNm" data-valid-type="alpahNumeric" data-valid-name="User Name"/>
+ * 			ex) <input type="text" name="userNm" data-valid-type="alphaNumeric" data-valid-name="User Name"/>
  *
  * 		2. data-valid-type
  * 			numeric, alphaNumeric, email, cellPhone, ipAddress

+ 64 - 3
src/main/webapp/ux/style24_link.js

@@ -12,9 +12,8 @@ const _PAGE_CUSTOMER_JOIN = _frontUrl + "/customer/join/form";						// 고객 >
 const _PAGE_CUSTOMER_SNS_JOIN = _frontUrl + "/customer/sns/join/form";				// 고객 > SNS가입
 const _PAGE_CUSTOMER_JOIN_COMPLETE = _frontUrl + "/customer/join/complete/form";	// 고객 > 고객가입 > 완료페이지
 const _PAGE_CUSTOMER_ID_FIND = _frontUrl + "/customer/id/find/form";				// 고객 > 아이디 찾기
-const _PAGE_CUSTOMER_ID_FIND_RESULT = _frontUrl +"/customer/id/find/result/form";	// 고객 > 아이디 찾기 > 결과페이지
 const _PAGE_CUSTOMER_PWD_FIND = _frontUrl + "/customer/pwd/find/form";				// 고객 > 비밀번호 찾기
-const _PAGE_CUSTOMER_PWD_FIND_RESULT = _frontUrl +"/customer/pwd/find/result/form";	// 고객 > 비밀번호 찾기 > 결과페이지
+const _PAGE_CUSTOMER_DORMANT = _frontUrl + "/customer/dormant/certify/form";		// 고객 > 휴면회원
 
 //== 상품상세 ==/
 
@@ -25,7 +24,7 @@ const _PAGE_CUSTOMER_PWD_FIND_RESULT = _frontUrl +"/customer/pwd/find/result/for
 //== 마이페이지 ==/
 const _PAGE_MYPAGE = _frontUrl + "/mypage/main/form";							// 마이페이지 > 메인
 const _PAGE_ORDER_LIST = _frontUrl + "/mypage/order/list/form";					// 마이페이지 > 주문확인/배송조회
-const _PAGE_ORDER_DETAIL = _frontUrl + "/mypage/order/detail/form?ordNo=";		// 마이페이지 > 주문/배송 상세
+const _PAGE_ORDER_DETAIL = _frontUrl + "/mypage/order/detail/form";				// 마이페이지 > 주문/배송 상세
 const _PAGE_CRS_LIST = _frontUrl + "/mypage/crs/list/form";						// 마이페이지 > 취소/교환/반품 목록
 const _PAGE_RESTOCK = _frontUrl + "/mypage/restock/form";						// 마이페이지 > 재입고 알림 내역
 const _PAGE_REVIEW = _frontUrl + "/mypage/review/form";							// 마이페이지 > 리뷰
@@ -65,3 +64,65 @@ var cfnGoToPage = function(page, ithrCd) {
 	if (ithrCd) params += "&ithrCd=" + ithrCd;
 	document.location.href = params;
 }
+
+/**
+ * @type   : function
+ * @access : public
+ * @desc   : 나이스 휴대폰 인증
+ * <pre>
+ *     cfnOpenCellphoneCertify();
+ *     호출된 페이지에서
+ *     PC : fnNiceCallBack(encData) 콜백 함수 생성 후 encData 가지고 호출 처리
+ *     MO : redirectUrl 호출하는 페이지에서 넣어줘야됨
+ * </pre>
+ * @param  redirectUrl - 모바일에서 사용 페이지이동으로 하기 때문에
+ * @param  custparams - 회원정보수정 화면에서 사용함
+ * @since  : 2021/02/09
+ * @author : jsshin
+ */
+var cfnOpenCellphoneCertify = function (redirectUrl, custparams) {
+	var actionUrl = _frontUrl + "/customer/nice/cellphone/form";
+	var popupWidth = 450;
+	var popupHeight = 700;
+	var popupX = (window.screen.width / 2) - (popupWidth / 2);
+	var popupY = (window.screen.height / 3) - (popupHeight / 3);
+	if ('P' === _frontGb) {
+		window.open(actionUrl, "popupCellphone", "top=" + popupY + ", left=" + popupX + ", width=" + popupWidth + ", height=" + popupHeight + ", fullscreen=no,menubar=no,status=no,toolbar=no,titlebar=yes,location=no,scrollbar=no");
+	} else {
+		if (!gagajf.isNull(redirectUrl)) {
+			actionUrl = actionUrl + "?redirectUrl=" + redirectUrl;
+			if (!gagajf.isNull(custparams)) {
+				actionUrl = actionUrl + "&custparams=" + custparams;
+			}
+			document.location.href = actionUrl;
+		}
+	}
+};
+
+/**
+ * @type   : function
+ * @access : public
+ * @desc   : 나이스 휴대폰 인증
+ * <pre>
+ *     cfnOpenIpinCertify();
+ *     호출된 페이지에서
+ *     PC : fnNiceCallBack(encData) 콜백 함수 생성 후 encData 가지고 호출 처리
+ *     MO :
+ * </pre>
+ * @since  : 2021/02/09
+ * @author : jsshin
+ */
+var cfnOpenIpinCertify = function (redirectUrl) {
+	var actionUrl = _frontUrl + "/customer/nice/ipin/form";
+	var popupWidth = 450;
+	var popupHeight = 700;
+	var popupX = (window.screen.width / 2) - (popupWidth / 2);
+	var popupY = (window.screen.height / 3) - (popupHeight / 3);
+	if ('P' === _frontGb) {
+		window.open(actionUrl, "popupIpin", "top=" + popupY + ", left=" + popupX + ", width=" + popupWidth + ", height=" + popupHeight + ", fullscreen=no,menubar=no,status=no,toolbar=no,titlebar=yes,location=no,scrollbar=no");
+	} else {
+		if (!gagajf.isNull(redirectUrl)) {
+			document.location.href = actionUrl + "?redirectUrl=" + redirectUrl;
+		}
+	}
+};