Sfoglia il codice sorgente

Merge branch 'develop' of http://112.172.147.34:4936/style24/style24.front into develop

jsshin 5 anni fa
parent
commit
acc9469859
75 ha cambiato i file con 1166 aggiunte e 183 eliminazioni
  1. 1 3
      pom.xml
  2. 10 10
      src/main/java/com/style24/front/biz/dao/TsfLoginDao.java
  3. 20 17
      src/main/java/com/style24/front/biz/service/TsfLoginService.java
  4. 3 3
      src/main/java/com/style24/front/biz/web/TsfIndexController.java
  5. 1 1
      src/main/java/com/style24/front/support/config/TsfWebMvcConfig.java
  6. 22 0
      src/main/java/com/style24/front/support/exception/TsfUsernameNotFoundException.java
  7. 21 8
      src/main/java/com/style24/front/support/security/TsfAuthenticationProvider.java
  8. 1 1
      src/main/java/com/style24/front/support/security/config/TsfSecurityConfig.java
  9. 2 2
      src/main/java/com/style24/front/support/security/filter/TsfAuthenticationFilter.java
  10. 8 8
      src/main/java/com/style24/front/support/security/handler/TsfLoginFailureHandler.java
  11. 6 6
      src/main/java/com/style24/front/support/security/handler/TsfLoginSuccessHandler.java
  12. 4 4
      src/main/java/com/style24/front/support/security/handler/TsfRememberMeSuccessHandler.java
  13. 2 1
      src/main/java/com/style24/front/support/startup/TsfApplication.java
  14. 88 86
      src/main/java/com/style24/persistence/mybatis/shop/TsfLogin.xml
  15. 2 2
      src/main/resources/config/application.yml
  16. 234 0
      src/main/webapp/WEB-INF/views/web/SigninFormWeb.html
  17. 2 2
      src/main/webapp/WEB-INF/views/web/common/error/500Web.html
  18. 3 2
      src/main/webapp/WEB-INF/views/web/common/fragments/GnbWeb.html
  19. 1 0
      src/main/webapp/WEB-INF/views/web/common/fragments/HeadWeb.html
  20. BIN
      src/main/webapp/images/btn_top_close.png
  21. BIN
      src/main/webapp/images/pc/bg_coupon_code1.png
  22. BIN
      src/main/webapp/images/pc/btn_close_code.png
  23. BIN
      src/main/webapp/images/pc/cursor_zoom.png
  24. BIN
      src/main/webapp/images/pc/ico_admin.png
  25. BIN
      src/main/webapp/images/pc/ico_bracket.png
  26. BIN
      src/main/webapp/images/pc/ico_chk_rdi.png
  27. BIN
      src/main/webapp/images/pc/ico_chk_rdi_bak.png
  28. BIN
      src/main/webapp/images/pc/ico_close1.png
  29. BIN
      src/main/webapp/images/pc/ico_cp_down.png
  30. BIN
      src/main/webapp/images/pc/ico_dp_arrow.png
  31. BIN
      src/main/webapp/images/pc/ico_like2.png
  32. BIN
      src/main/webapp/images/pc/ico_myinfo_arrow.png
  33. BIN
      src/main/webapp/images/pc/ico_mysm_arrow.png
  34. BIN
      src/main/webapp/images/pc/ico_pop_cls02.png
  35. BIN
      src/main/webapp/images/pc/ico_saletag.png
  36. BIN
      src/main/webapp/images/pc/ico_star01.png
  37. BIN
      src/main/webapp/images/pc/ico_star02.png
  38. BIN
      src/main/webapp/images/pc/ico_timer.png
  39. BIN
      src/main/webapp/images/pc/ico_trash.png
  40. BIN
      src/main/webapp/images/pc/slide_next.png
  41. BIN
      src/main/webapp/images/pc/slide_prev.png
  42. BIN
      src/main/webapp/images/pc/star_empty.png
  43. BIN
      src/main/webapp/images/pc/thumb/attend_banner.jpg
  44. BIN
      src/main/webapp/images/pc/thumb/bigbanner_slide02.png
  45. BIN
      src/main/webapp/images/pc/thumb/comment_banner.jpg
  46. BIN
      src/main/webapp/images/pc/thumb/dp_exhibition_pr01.jpg
  47. BIN
      src/main/webapp/images/pc/thumb/dp_exhibition_pr02.jpg
  48. BIN
      src/main/webapp/images/pc/thumb/dp_exhibition_pr03.jpg
  49. BIN
      src/main/webapp/images/pc/thumb/dp_hd_img01.jpg
  50. BIN
      src/main/webapp/images/pc/thumb/dp_submain_img01.jpg
  51. BIN
      src/main/webapp/images/pc/thumb/dp_submain_img02.jpg
  52. BIN
      src/main/webapp/images/pc/thumb/dp_submain_img03.jpg
  53. BIN
      src/main/webapp/images/pc/thumb/dp_submain_img04.jpg
  54. BIN
      src/main/webapp/images/pc/thumb/ev_cmt_img02.jpg
  55. BIN
      src/main/webapp/images/pc/thumb/ev_cmt_img03.jpg
  56. BIN
      src/main/webapp/images/pc/thumb/renewal_banner.jpg
  57. BIN
      src/main/webapp/images/pc/thumb/tmp_cartColor1.jpg
  58. BIN
      src/main/webapp/images/pc/thumb/tmp_desc_bnr.jpg
  59. BIN
      src/main/webapp/images/pc/thumb/tmp_desc_mds.jpg
  60. BIN
      src/main/webapp/images/pc/thumb/tmp_detail_desc1.jpg
  61. BIN
      src/main/webapp/images/pc/thumb/tmp_detail_desc2.jpg
  62. BIN
      src/main/webapp/images/pc/thumb/tmp_fabric_desc1.jpg
  63. BIN
      src/main/webapp/images/pc/thumb/tmp_gift_empty.jpg
  64. BIN
      src/main/webapp/images/pc/thumb/tmp_label_desc1.jpg
  65. BIN
      src/main/webapp/images/pc/thumb/tmp_label_desc2.jpg
  66. BIN
      src/main/webapp/images/pc/thumb/tmp_outfit_desc1.jpg
  67. BIN
      src/main/webapp/images/pc/thumb/tmp_outfit_desc2.jpg
  68. BIN
      src/main/webapp/images/pc/thumb/tmp_outfit_desc3.jpg
  69. BIN
      src/main/webapp/images/pc/thumb/tmp_pdDetail7_1.jpg
  70. BIN
      src/main/webapp/images/pc/thumb/tmp_pdLookbook2.jpg
  71. BIN
      src/main/webapp/images/pc/thumb/tmp_pdLookbook3.jpg
  72. BIN
      src/main/webapp/images/pc/thumb/tmp_pdTogether1.jpg
  73. 350 25
      src/main/webapp/ux/pc/css/common.css
  74. 376 0
      src/main/webapp/ux/plugins/mcxdialog/mcxdialog_ui.js
  75. 9 2
      src/main/webapp/ux/style24_link.js

+ 1 - 3
pom.xml

@@ -16,9 +16,7 @@
 		<!-- Maven module core -->
 		<dependency>
 			<groupId>com.style24.core</groupId>
-			<artifactId>style24.core</artifactId>
-			<version>0.0.1-SNAPSHOT</version>
-			<scope>compile</scope>
+			<artifactId>style24-core</artifactId>
 		</dependency>
 		<!--// Maven module core -->
 		

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

@@ -15,29 +15,29 @@ public interface TsfLoginDao {
 
 	/**
 	 * 로그인체크정보 조회
-	 * @param customer - 고객정보
-	 * @return 고객정보
+	 * @param login - 로그인 정보
+	 * @return
 	 * @author gagamel
 	 * @date 2020. 2. 3
 	 */
-	Login getLoginCheckInfo(Login customer);
+	Login getLoginCheckInfo(Login login);
 
 	/**
 	 * 로그인실패 남기기
-	 * @param customer - 고객정보
+	 * @param login - 로그인 정보
 	 * @author gagamel
 	 * @date 2020. 2. 3
 	 */
-	void createLoginFail(Login customer);
+	void createLoginFail(Login login);
 
 	/**
 	 * 로그인 실패건수 조회
-	 * @param customer - 고객정보
+	 * @param login - 로그인 정보
 	 * @return 로그인 실패건수
 	 * @author gagamel
 	 * @date 2020. 2. 3
 	 */
-	int getLoginFailCount(Login customer);
+	int getLoginFailCount(Login login);
 
 	/**
 	 * 최종로그인일시 Update
@@ -49,11 +49,11 @@ public interface TsfLoginDao {
 
 	/**
 	 * 로그인이력 남기기
-	 * @param customer - 고객정보
+	 * @param login - 로그인 정보
 	 * @author gagamel
 	 * @date 2020. 2. 3
 	 */
-	void createLoginHistory(Login customer);
+	void createLoginHistory(Login login);
 
 //	/**
 //	 * 로그인 세션정보 조회
@@ -62,7 +62,7 @@ public interface TsfLoginDao {
 //	 * @author gagamel
 //	 * @date 2020. 2. 3
 //	 */
-//	FoLogin getLoginSessionInfo(FoLogin customer);
+//	Login getLoginSessionInfo(FoLogin customer);
 
 	/**
 	 * 로그인유지토큰 생성

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

@@ -29,15 +29,15 @@ public class TsfLoginService {
 
 	/**
 	 * 로그인체크정보 조회
-	 * @param customer - 고객정보
-	 * @return 고객정보
+	 * @param login - 로그인 정보
+	 * @return
 	 * @author gagamel
 	 * @since 2020. 2. 3
 	 */
-	public Login getLoginCheckInfo(Login customer) {
-		customer.setIpAddr(TsfSession.getIpAddress());
-		customer.setSiteCd(TscConstants.Site.STYLE24.value());
-		return loginDao.getLoginCheckInfo(customer);
+	public Login getLoginCheckInfo(Login login) {
+		login.setIpAddr(TsfSession.getIpAddress());
+		login.setSiteCd(TscConstants.Site.STYLE24.value());
+		return loginDao.getLoginCheckInfo(login);
 	}
 
 	/**
@@ -70,20 +70,20 @@ public class TsfLoginService {
 
 	/**
 	 * 로그인실패 남기기. 로그인실패여부가 "N:성공"이면 실패건수 0으로 초기화
-	 * @param custId - 고객ID
+	 * @param custNo - 고객번호
 	 * @param loginFailYn - 로그인실패여부(Y:실패, N:성공)
 	 * @author gagamel
 	 * @since 2020. 2. 3
 	 */
 	@Transactional("shopTxnManager")
-	public void createLoginFail(String custId, String loginFailYn) {
-		Login customer = new Login();
-		customer.setCustId(custId);
-		customer.setIpAddr(TsfSession.getIpAddress());
-		customer.setSiteCd(TscConstants.Site.STYLE24.value());
-		customer.setLoginFailYn(loginFailYn);
-
-		loginDao.createLoginFail(customer);
+	public void createLoginFail(Integer custNo, String loginFailYn) {
+		Login login = new Login();
+		login.setCustNo(custNo);
+		login.setIpAddr(TsfSession.getIpAddress());
+		login.setSiteCd(TscConstants.Site.STYLE24.value());
+		login.setLoginFailYn(loginFailYn);
+
+		loginDao.createLoginFail(login);
 	}
 
 	/**
@@ -105,7 +105,7 @@ public class TsfLoginService {
 	/**
 	 * 로그인유지토큰 생성
 	 * @param custNo - 고객번호
-	 * @param password - 비밀번호
+	 * @param remembermeToken - Rememberme토큰
 	 * @param expiry - 만료기간
 	 * @author gagamel
 	 * @since 2020. 6. 17
@@ -134,7 +134,10 @@ public class TsfLoginService {
 
 	/**
 	 * 로그인유지토큰 갱신
-	 * @param token - 토큰 정보
+	 * @param custNo - 고객번호
+	 * @param prevRemembermeToken - 기존 Rememberme토큰
+	 * @param remembermeToken - Rememberme토큰
+	 * @param expiry - 만료기간
 	 * @author gagamel
 	 * @since 2020. 6. 17
 	 */

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

@@ -54,14 +54,14 @@ public class TsfIndexController extends TsfBaseController {
 
 		if (status != null) {
 			Integer statusCode = Integer.valueOf(status.toString());
-			log.debug("statusCode: {}", statusCode);
+			log.info("statusCode: {}", statusCode);
 
 			if (statusCode == GagaResponseStatus.NOT_FOUND.getCode()) {
 				mav.addObject("status", GagaResponseStatus.NOT_FOUND.getCode());
 
 				// 404 오류 시 잘못된 링크 유입 시 몰메인으로 이동 처리
 				String prevRequestUri = (String)request.getAttribute(RequestDispatcher.FORWARD_REQUEST_URI);
-				log.debug("prevRequestUri: {}", prevRequestUri);
+				log.info("prevRequestUri: {}", prevRequestUri);
 				if (prevRequestUri.startsWith("/m")) {
 					response.sendRedirect("/");
 				}
@@ -126,7 +126,7 @@ public class TsfIndexController extends TsfBaseController {
 		mav.addObject("front", env.getProperty("domain.front"));
 
 		// 로그인 페이지로
-		mav.setViewName(super.getDeviceViewName("Signin"));
+		mav.setViewName(super.getDeviceViewName("SigninForm"));
 
 		return mav;
 	}

+ 1 - 1
src/main/java/com/style24/front/support/config/TsfWebMvcConfig.java

@@ -59,7 +59,7 @@ public class TsfWebMvcConfig implements WebMvcConfigurer {
 	public void addInterceptors(InterceptorRegistry registry) {
 		final String[] excludePathPatterns = new String[] {
 			"/", "/index", "/signin/**",
-			"/image/**", "/ux/**",
+			"/images/**", "/ux/**",
 			"/error/**", "/data/**",
 			"/login", "/logout"
 		};

+ 22 - 0
src/main/java/com/style24/front/support/exception/TsfUsernameNotFoundException.java

@@ -0,0 +1,22 @@
+package com.style24.front.support.exception;
+
+import org.springframework.security.core.AuthenticationException;
+
+/**
+ * 로그인 정보가 없을 경우 발생시키는 예외
+ * 
+ * @author gagamel
+ * @since 2021. 2. 15
+ */
+@SuppressWarnings("serial")
+public class TsfUsernameNotFoundException extends AuthenticationException {
+
+	public TsfUsernameNotFoundException(String msg) {
+		super(msg);
+	}
+
+	public TsfUsernameNotFoundException(String msg, Throwable t) {
+		super(msg, t);
+	}
+
+}

+ 21 - 8
src/main/java/com/style24/front/support/security/TsfAuthenticationProvider.java

@@ -11,7 +11,6 @@ import org.springframework.security.authentication.UsernamePasswordAuthenticatio
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.AuthenticationException;
 import org.springframework.security.core.authority.SimpleGrantedAuthority;
-import org.springframework.security.core.userdetails.UsernameNotFoundException;
 import org.springframework.stereotype.Component;
 
 import com.style24.core.support.message.TscMessageByLocale;
@@ -21,6 +20,7 @@ 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.TsfUsernameNotFoundException;
 import com.style24.persistence.domain.Login;
 
 import lombok.extern.slf4j.Slf4j;
@@ -69,42 +69,55 @@ public class TsfAuthenticationProvider implements AuthenticationProvider {
 
 		// 로그인정보 조회
 		Login loginInfo = loginService.getLoginCheckInfo(loginParam);
-		log.debug("loginInfo: {}", loginInfo);
+		log.info("loginInfo: {}", loginInfo);
 
 		if (loginInfo == null) {
-			log.debug(String.format("Customer with ID=%s was not found!", loginId));
-			throw new UsernameNotFoundException(message.getMessage("LOGN_0001"));
+			log.info(String.format("Customer with ID=%s was not found!", loginId));
+			throw new TsfUsernameNotFoundException(message.getMessage("LOGN_0001"));
 		}
 
 		// 로그인 실패누적건수가 5이면
 		if (loginInfo.getLoginFailCnt() == 5) {
+			// 로그인 실패 남기기
+			loginService.createLoginFail(loginInfo.getCustNo(), "Y");
+
 //			throw new BadCredentialsException(message.getMessage("LOGN_0005"));
 			throw new TsfLockedAccountException(message.getMessage("LOGN_0005"));
 		}
 
 		/// SNS로그인이 아닌 일반로그인 이면
 		if (!loginId.startsWith(TsfConstants.SNSLOGIN_PREFIX)) {
-			log.debug("encoded pwd: {}", passwordEncoder.encode(passwd));
+			log.info("encoded password: {}", passwordEncoder.encode(passwd));
 			boolean isMatch = passwordEncoder.matches(passwd, loginInfo.getPasswd());
-			log.debug("isMatch: {}", isMatch);
+			log.info("Password is match?: {}", isMatch);
 
 			if (!isMatch) {
-//				// 로그인 실패 남기기
-//				customerService.createLoginFail(loginInfo.getCustId(), "Y");
+				// 로그인 실패 남기기
+				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"));
 		}
 

+ 1 - 1
src/main/java/com/style24/front/support/security/config/TsfSecurityConfig.java

@@ -32,7 +32,7 @@ public class TsfSecurityConfig extends WebSecurityConfigurerAdapter {
 
 	private static final String[] UNAUTHORIZED_RESOURCE_LIST = new String[] {"/*", "/index", "/signin/**"};
 
-	private static final String[] UNSECURED_RESOURCE_LIST = new String[] {"/image/**", "/ux/**", "/data/**"};
+	private static final String[] UNSECURED_RESOURCE_LIST = new String[] {"/images/**", "/ux/**", "/data/**"};
 
 	@Autowired
 	private TsfAuthenticationProvider authenticationProvider;

+ 2 - 2
src/main/java/com/style24/front/support/security/filter/TsfAuthenticationFilter.java

@@ -35,7 +35,7 @@ public class TsfAuthenticationFilter extends UsernamePasswordAuthenticationFilte
 			// 로그인ID: SNS_TYPE-SNS_JOIN_ID
 			// 비밀번호: 이메일
 			loginParams.setString("loginId", loginParams.getString("snsType") + "-" + loginParams.getString("snsJoinId"));
-			loginParams.setString("passwd", loginParams.getString("email")); // SNS로그인 시 불필요해서 이메일체크를 위해 추가
+			loginParams.setString("passwd", loginParams.getString("email")); // SNS로그인 시 이메일체크를 위해 추가
 		} else { // 일반로그인
 			if (StringUtils.isNotBlank(loginParams.getString("loginId"))) {
 				loginParams.setString("loginId", loginParams.getString("loginId").trim());
@@ -46,7 +46,7 @@ public class TsfAuthenticationFilter extends UsernamePasswordAuthenticationFilte
 			}
 		}
 
-		log.debug("loginParams: {}", loginParams);
+		log.info("loginParams: {}", loginParams);
 
 		UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(
 			loginParams.getString("loginId"), loginParams.getString("passwd"));

+ 8 - 8
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.springframework.beans.factory.annotation.Autowired;
+import org.apache.commons.lang3.StringUtils;
 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,16 +34,10 @@ 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("custId"), "Y");
-
 		GagaMap result = new GagaMap();
 		result.setString("message", exception.getMessage());
 
@@ -61,6 +55,12 @@ 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));
+
 		GagaStringUtil.write(response, result);
 	}
 

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

@@ -41,18 +41,15 @@ public class TsfLoginSuccessHandler implements AuthenticationSuccessHandler {
 		"/customer/join/form",				// 회원가입
 		"/customer/sns/join/form",			// SNS 회원가입
 		"/customer/id/find/form",			// 아이디찾기
-		"/customer/id/find/result/form",	// 아이디찾기
+		"/customer/id/find/result/form",	// 아이디찾기완료
 		"/customer/pwd/find/form",			// 비밀번호찾기
-		"/customer/pwd/find/result/form",	// 비밀번호완료
+		"/customer/pwd/find/result/form",	// 비밀번호찾기완료
 		"/customer/join/complete/form"		// 회원가입완료
 	};
 
 	@Autowired
 	private TsfLoginService loginService;
 
-//	@Autowired
-//	private FoCustomerService customerService;
-
 	@Override
 	public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
 		// 로그인 상세 정보
@@ -62,7 +59,7 @@ public class TsfLoginSuccessHandler implements AuthenticationSuccessHandler {
 		Integer custNo = loginDetails.getLoginInfo().getCustNo();
 		int failCnt = loginService.getLoginFailCount(custNo);
 		if (failCnt > 0) {
-			loginService.createLoginFail(loginDetails.getLoginInfo().getCustId(), "N");
+			loginService.createLoginFail(loginDetails.getLoginInfo().getCustNo(), "N");
 		}
 
 		// 최종로그인일시 Update
@@ -125,6 +122,9 @@ public class TsfLoginSuccessHandler implements AuthenticationSuccessHandler {
 		HttpSession session = request.getSession(true);
 		session.setMaxInactiveInterval(1800);
 		session.setAttribute("session", loginDetails);
+
+		// 세션에 저장된 로그인실패건수 제거
+		session.removeAttribute("loginFailCnt");
 	}
 
 }

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

@@ -29,9 +29,6 @@ public class TsfRememberMeSuccessHandler implements AuthenticationSuccessHandler
 	@Autowired
 	private TsfLoginService loginService;
 
-//	@Autowired
-//	private FoCustomerService customerService;
-
 	@Override
 	public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
 		// 로그인 상세 정보
@@ -41,7 +38,7 @@ public class TsfRememberMeSuccessHandler implements AuthenticationSuccessHandler
 		Integer custNo = loginDetails.getLoginInfo().getCustNo();
 		int failCnt = loginService.getLoginFailCount(custNo);
 		if (failCnt > 0) {
-			loginService.createLoginFail(loginDetails.getLoginInfo().getCustId(), "N");
+			loginService.createLoginFail(loginDetails.getLoginInfo().getCustNo(), "N");
 		}
 
 		// 최종로그인일시 Update
@@ -77,6 +74,9 @@ public class TsfRememberMeSuccessHandler implements AuthenticationSuccessHandler
 		HttpSession session = request.getSession(true);
 		session.setMaxInactiveInterval(1800);
 		session.setAttribute("session", loginDetails);
+
+		// 세션에 저장된 로그인실패건수 제거
+		session.removeAttribute("loginFailCnt");
 	}
 
 }

+ 2 - 1
src/main/java/com/style24/front/support/startup/TsfApplication.java

@@ -10,6 +10,7 @@ import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
 import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
 import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration;
+import org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration;
 import org.springframework.cache.annotation.EnableCaching;
 import org.springframework.context.annotation.ComponentScan;
 import org.springframework.context.annotation.Configuration;
@@ -28,7 +29,7 @@ import com.gagaframework.web.core.GagaConstants;
  */
 @EnableCaching
 @Configuration
-@EnableAutoConfiguration(exclude = {DataSourceTransactionManagerAutoConfiguration.class, DataSourceAutoConfiguration.class})
+@EnableAutoConfiguration(exclude = {DataSourceTransactionManagerAutoConfiguration.class, DataSourceAutoConfiguration.class, ErrorMvcAutoConfiguration.class})
 @ComponentScan(basePackages = {GagaConstants.GAGA_PACKAGE, TscConstants.BASE_PACKAGE})
 @Slf4j
 public class TsfApplication {

+ 88 - 86
src/main/java/com/style24/persistence/mybatis/shop/TsfLogin.xml

@@ -5,31 +5,37 @@
 	<!-- 로그인체크 정보 조회 -->
 	<select id="getLoginCheckInfo" parameterType="Login" resultType="Login">
 		/* TsfLogin.getLoginCheckInfo */
-		SELECT CUST_NO                                      --고객번호
-		     , CUST_ID                                      --고객ID
-		     , CUST_NM                                      --고객명
-		     , PASSWD                                       --비밀번호
-		     , CUST_GB                                      --고객구분
-		     , FN_GET_CODE_NM('G100',CUST_GB) AS CUST_GB_NM --고객구분명
-		     , CUST_STAT                                    --회원상태
-		     , EMAIL                                        --이메일
-		     , SNS_TYPE                                     --SNS유형
-		     , SNS_JOIN_ID                                  --SNS가입ID
-		     , NVL((SELECT LOGIN_FAIL_CNT
-		            FROM   TB_LOGIN_FAIL
-		            WHERE  LOGIN_ID = TO_CHAR(A.CUST_NO)
-		            AND    IP_ADDR = #{ipAddr}
-		            AND    SITE_CD = #{siteCd}
-		           ),0)    AS LOGIN_FAIL_CNT                --로그인실패건수
+		SELECT CUST_NO                                          /*고객번호*/
+		     , CUST_ID                                          /*고객ID*/
+		     , CUST_NM                                          /*고객명*/
+		     , PASSWD                                           /*비밀번호*/
+		     , CUST_GB                                          /*고객구분*/
+		     , FN_GET_CODE_NM('G100',CUST_GB) AS CUST_GB_NM     /*고객구분명*/
+		     , CUST_STAT                                        /*회원상태*/
+		     , EMAIL                                            /*이메일*/
+		     , #{snsType}                     AS SNS_TYPE       /*SNS유형*/
+		     , CASE WHEN #{snsType} = 'NV' THEN NV_JOIN_ID
+		            WHEN #{snsType} = 'KK' THEN KK_JOIN_ID
+		            WHEN #{snsType} = 'YS' THEN YS_JOIN_ID
+		            ELSE ''
+		       END                            AS SNS_JOIN_ID    /*SNS가입ID*/
+		     , IFNULL((SELECT LOGIN_FAIL_CNT
+		               FROM   TB_LOGIN_FAIL
+		               WHERE  CUST_NO = A.CUST_NO
+		               AND    IP_ADDR = #{ipAddr}
+		               AND    SITE_CD = #{siteCd}
+		              ),0)                    AS LOGIN_FAIL_CNT /*로그인실패건수*/
 		FROM   TB_CUSTOMER A
-		WHERE  CUST_STAT <![CDATA[<>]]> '40'                --전환대상고객제외
+		WHERE  1 = 1
 		<choose>
-		    <when test="snsType != null and snsType != ''"> <!-- SNS로그인 -->
-		AND    (
-		        SNS_TYPE||'-'||SNS_JOIN_ID = #{custId}
-		        OR
-		        EMAIL = #{email}
-		       )
+		    <when test="snsType == 'NV'"> <!-- SNS로그인:네이버 -->
+		AND    NV_JOIN_ID = #{custId}
+		    </when>
+		    <when test="snsType == 'KK'"> <!-- SNS로그인:카카오 -->
+		AND    KK_JOIN_ID = #{custId}
+		    </when>
+		    <when test="snsType == 'YS'"> <!-- SNS로그인:YES24 -->
+		AND    YS_JOIN_ID = #{custId}
 		    </when>
 		    <otherwise> <!-- 일반로그인 -->
 		AND    CUST_ID = #{custId}
@@ -40,36 +46,41 @@
 	<!-- 로그인실패 남기기 -->
 	<insert id="createLoginFail" parameterType="Login">
 		/* TsfLogin.createLoginFail */
-		MERGE INTO TB_LOGIN_FAIL
-		USING (
-		       SELECT TO_CHAR(CUST_NO) AS CUST_NO
-		       FROM   TB_CUSTOMER
-		       WHERE  CUST_ID = #{custId}
-		      ) B
-		ON    (
-		       LOGIN_ID = B.CUST_NO
-		AND    IP_ADDR = #{ipAddr}
-		AND    SITE_CD = #{siteCd}
-		      )
-		WHEN MATCHED THEN
-		    UPDATE
-		    SET    LOGIN_FAIL_CNT = DECODE(#{loginFailYn},'Y',LOGIN_FAIL_CNT + 1,0)
-		         , UPD_NO = B.CUST_NO
-		         , UPD_DT = NOW()
-		WHEN NOT MATCHED THEN
-		    INSERT (LOGIN_ID, IP_ADDR, SITE_CD, LOGIN_FAIL_CNT, REG_ID, REG_DT, UPD_NO, UPD_DT)
-		    VALUES (B.CUST_NO, #{ipAddr}, #{siteCd}, 1, B.CUST_NO, NOW(), B.CUST_NO, NOW())
+		INSERT INTO TB_LOGIN_FAIL (
+		       CUST_NO
+		     , IP_ADDR
+		     , SITE_CD
+		     , LOGIN_FAIL_CNT
+		     , REG_NO
+		     , REG_DT
+		     , UPD_NO
+		     , UPD_DT
+		)
+		VALUES (
+		       #{custNo}
+		     , #{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}
+		     , UPD_DT = NOW()
 	</insert>
 
 	<!-- 로그인 실패건수 조회 -->
 	<select id="getLoginFailCount" parameterType="Login" resultType="int">
 		/* TsfLogin.getLoginFailCount */
-		SELECT NVL((SELECT LOGIN_FAIL_CNT
-		            FROM   TB_LOGIN_FAIL
-		            WHERE  LOGIN_ID = #{custNo}
-		            AND    IP_ADDR = #{ipAddr}
-		            AND    SITE_CD = #{siteCd}
-		           ),0)
+		SELECT IFNULL((SELECT LOGIN_FAIL_CNT
+		               FROM   TB_LOGIN_FAIL
+		               WHERE  CUST_NO = #{custNo}
+		               AND    IP_ADDR = #{ipAddr}
+		               AND    SITE_CD = #{siteCd}
+		              ),0) AS CNT
 		FROM   DUAL
 	</select>
 
@@ -88,16 +99,16 @@
 		/* TsfLogin.createLoginHistory */
 		INSERT INTO TB_LOGIN_HST (
 		       LOGIN_HST_SQ
-		     , LOGIN_ID
+		     , CUST_NO
 		     , IP_ADDR
 		     , SITE_CD
 		     , FRONT_GB
 		     , LOGIN_DT
-		     , REG_ID
+		     , REG_NO
 		     , REG_DT
 		)
 		VALUES (
-		       SEQ_LOGIN_HST.NEXTVAL
+		       NULL
 		     , #{custNo}
 		     , #{ipAddr}
 		     , #{siteCd}
@@ -111,51 +122,42 @@
 	<!-- 로그인 세션정보 조회 -->
 	<select id="getLoginSessionInfo" parameterType="Login" resultType="Login">
 		/* TsfLogin.getLoginSessionInfo */
-		SELECT CUST_NO                                                --고객번호
-		     , CUST_ID                                                --고객ID
-		     , CUST_NM                                                --고객명
-		     , PASSWD                                                 --비밀번호
-		     , CELL_PHNNO                                             --휴대전화번호
-		     , EMAIL                                                  --이메일
-		     , CUST_GB                                                --회원구분코드
-		     , FN_GET_CODE_NM('G100',CUST_GB)        AS CUST_GB_NM    --회원구분명
-		     , CUST_GRADE                                             --회원등급코드
-		     , FN_GET_CODE_NM('G110',CUST_GRADE)     AS CUST_GRADE_NM --회원등급명
-		     , SITE_CD                                                --사이트코드
-		     , TO_CHAR(LOGIN_LDT,'YYYYMMDDHH24MISS') AS LOGIN_LDT     --최종로그인일시
-		     , MANAGED_RSN                                            --관리대상지정사유(공통코드G120)
+		SELECT CUST_NO                                                /*고객번호*/
+		     , CUST_ID                                                /*고객ID*/
+		     , CUST_NM                                                /*고객명*/
+		     , PASSWD                                                 /*비밀번호*/
+		     , CELL_PHNNO                                             /*휴대전화번호*/
+		     , EMAIL                                                  /*이메일*/
+		     , CUST_GB                                                /*회원구분코드*/
+		     , FN_GET_CODE_NM('G100',CUST_GB)        AS CUST_GB_NM    /*회원구분명*/
+		     , CUST_GRADE                                             /*회원등급코드*/
+		     , FN_GET_CODE_NM('G110',CUST_GRADE)     AS CUST_GRADE_NM /*회원등급명*/
+		     , SITE_CD                                                /*사이트코드*/
+		     , TO_CHAR(LOGIN_LDT,'YYYYMMDDHH24MISS') AS LOGIN_LDT     /*최종로그인일시*/
+		     , MANAGED_RSN                                            /*관리대상지정사유(공통코드G120)*/
 		     , CASE WHEN ADD_MONTHS(PASSWD_CHG_DT,6) <![CDATA[<]]> NOW() THEN 'Y'
 		            ELSE 'N'
-		       END                                   AS PASSWD_CHG_YN --비밀번호변경도래여부
+		       END                                   AS PASSWD_CHG_YN /*비밀번호변경도래여부*/
 		FROM   TB_CUSTOMER A
 		WHERE  CUST_ID = #{custId}
-		AND    CUST_STAT = '10' --활동회원
+		AND    CUST_STAT = 'G104_10' /*활동회원*/
 	</select>
 
 	<!-- 로그인유지토큰 생성 -->
 	<insert id="createPersistentToken" parameterType="PersistentToken">
 		/* TsfLogin.createPersistentToken */
-		MERGE INTO TB_PERSISTENT_TOKEN
-		USING DUAL
-		ON    (
-		       CUST_NO = #{custNo}
-		       AND
-		       REMEMBERME_TOKEN = #{remembermeToken}
+		INSERT INTO TB_PERSISTENT_TOKEN (
+		       CUST_NO
+		     , REMEMBERME_TOKEN
+		     , LIMIT_DT
+		)
+		VALUES (
+		       #{custNo}
+		     , #{remembermeToken}
+		     , NOW()
 		)
-		WHEN MATCHED THEN
-		    UPDATE
-		    SET    LIMIT_DT = #{limitDt}
-		WHEN NOT MATCHED THEN
-		    INSERT (
-		            CUST_NO
-		          , REMEMBERME_TOKEN
-		          , LIMIT_DT
-		    )
-		    VALUES (
-		           #{custNo}
-		         , #{remembermeToken}
-		         , NOW()
-		    )
+		ON DUPLICATE KEY UPDATE
+		       LIMIT_DT = #{limitDt}
 	</insert>
 
 	<!-- 로그인유지토큰 조회 -->

+ 2 - 2
src/main/resources/config/application.yml

@@ -17,13 +17,13 @@ spring:
             repositories:
                 enabled: true
 
-server:
+#server:
 #    servlet:
 #        session:
 #            cookie:
 #                name: WSESSIONID
 #                secure: true
-    error.whitelabel.enabled: false
+#    error.whitelabel.enabled: false
 
 # 본인인증
 certify:

+ 234 - 0
src/main/webapp/WEB-INF/views/web/SigninFormWeb.html

@@ -0,0 +1,234 @@
+<!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  : SigninFormWeb.html
+ * @desc    : 로그인 Page
+ *============================================================================
+ * STYLE24
+ * Copyright(C) 2020 TSIT, All rights reserved.
+ *============================================================================
+ * VER  DATE         AUTHOR      DESCRIPTION
+ * ===  ===========  ==========  =============================================
+ * 1.0  2021.02.15   gagamel     최초 작성
+ *******************************************************************************
+ -->
+<body>
+
+<th:block layout:fragment="content">
+<div id="container" class="container mb">
+	<div class="wrap">
+			<div class="content login"> <!-- 페이지특정 클래스 = login -->
+				<div class="cont_head">
+					<h3>style24</h3>
+				</div>
+				<div class="cont_body">
+					<form class="form_wrap form_col_c form_full" role="form" name="loginForm" id="loginForm" th:action="@{/login}" method="post">
+						<div class="form_head">
+							<h4>로그인</h4>
+						</div> 
+						<div class="form_field mt0">
+							<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="아이디"/>
+								</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="password" name="passwd" class="form_control" placeholder="비밀번호 8자 ~ 20자 입력" maxlength="20" required="required" data-valid-name="비밀번호"/>
+								</div>
+							</div>
+						</div>
+						<div class="login_check">
+							<div class="form_field">
+								<input type="checkbox" id="chkSaveId"/><label for="chkSaveId"> <span>아이디 저장</span> </label>
+							</div>
+							<div class="btn_wrap">
+								<ul>
+									<li><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>
+						<!-- 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"> <!-- 캡차이미지 -->
+									</li>
+									<li class="captcha_btn_dual">
+										<button type="button" id="play_audio">새로고침</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="문자입력">
+									</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>
+							<!-- //보안문자 입력시 -->
+						</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>
+							</div>
+						</div>
+						<div class="sns_wrap">
+							<h5 class="sr-only">간편로그인</h5>
+							<ul>
+								<li>
+									<a href="javascript:void(0)">
+										<i class="ico ico_snslogin kakao"></i>
+										<span>카카오로 시작하기</span>
+									</a>
+								</li>
+								<li>
+									<a href="javascript:void(0)">
+										<i class="ico ico_snslogin naver"></i>
+										<span>네이버로 시작하기</span>
+									</a>
+								</li>
+								<li>
+									<a href="javascript:void(0)">
+										<i class="ico ico_snslogin yes24"></i>
+										<span>YES24로 시작하기</span>
+									</a>
+								</li>
+							</ul>
+						</div>
+						<div class="t_c mt30">
+							<button type="button" class="btn_nonMb"><span>비회원 주문조회</span></button>
+						</div>
+					</form>
+				</div>
+			</div>
+		</div>
+</div>
+
+<script th:inline="javascript">
+/*<![CDATA[*/
+	let ckLoginId = "ckLoginId";
+
+	// 로그인
+	var fnLogin = function() {
+		if (!gagajf.validation($('#loginForm'))) {
+			return;
+		}
+
+		let params = new Object();
+		params.loginId = $('#loginForm input[name=loginId]').val();
+		params.passwd = $('#loginForm input[name=passwd]').val();
+		
+		$.post($('#loginForm').prop('action')
+			, $.param(params)
+			, 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));
+						$(".t_err_login_fail").show();
+					}
+					
+					if (result.status == 'PWD_5WRONG') {
+						// 비밀번호 5회 이상 틀린 경우
+					} else if (result.status == 'DORMANT_CUST') {
+						// 휴면회원
+						//cfnGoToPage(_PAGE_DORMANT_GUIDE);
+					} else if (result.status == 'SECEDE_CUST') {
+						// 탈퇴회원
+					} else if (result.status == 'SESSION_EXPIRED') {
+						// 세션만료
+					}
+					
+					return; // 정상적으로 로그인 되지 않았으므로 return
+				}
+				
+				document.location.href = result.returnUrl;
+				
+// 				if (gagajf.isNull(result.returnUrl)) {
+// 					cfnGoToPage(_PAGE_MAIN);
+// 				} else {
+// 					if (result.returnUrl.indexOf(_PAGE_DIRECT_BUY) > -1) {
+// 						// 바로주문
+// 						jfOrderByMember();
+// 					} else if (result.returnUrl.indexOf(_PAGE_CUSTOMER_JOIN) > -1 ||
+// 						result.returnUrl.indexOf(_PAGE_CUSTOMER_ID_FIND) > -1 ||
+// 						result.returnUrl.indexOf(_PAGE_CUSTOMER_PW_FIND) > -1 ||
+// 						result.returnUrl.indexOf(_PAGE_CUSTOMER_JOIN_COMPLETE) > -1) {
+// 						cfnGoToPage(_PAGE_MAIN);
+// 					} else {
+// 						document.location.href = result.returnUrl;
+// 					}
+// 				}
+			}
+			, 'json');
+	}
+	
+	// Save ID
+	$('#chkSaveId').on('click', function() {
+		if ($(this).is(":checked")) {
+			if (!gagajf.isNull($('#loginForm input[name=loginId]').val())) {
+				gagajf.setCookie(ckLoginId, $('#loginForm input[name=loginId]').val(), 1);
+			}
+		} else {
+			if (!gagajf.isNull(gagajf.getCookie(ckLoginId)) && (gagajf.getCookie(ckLoginId) === $('#loginForm input[name=loginId]').val())) {
+				gagajf.setCookie(ckLoginId, $('#loginForm input[name=loginId]').val(), -1);
+			}
+		}
+	});
+	
+	// 카카오 로그인
+	var fnLoginKakao = function() {
+		document.location.href = _frontUrl + '/signin/kakologin';
+	};
+	
+	// 네이버 로그인
+	var fnLoginNaver = function() {
+		document.location.href = _frontUrl + '/signin/naverlogin';
+	};
+	
+	// YES24 로그인
+	var fnLoginYes24 = function() {
+		document.location.href = _frontUrl + '/signin/yes24login';
+	};
+
+	$(document).ready(function() {
+		$('#loginForm input[name=loginId]').val(gagajf.getCookie(ckLoginId));
+		if (gagajf.isNull($('#loginForm input[name=loginId]').val())) {
+			$('#loginForm input[name=loginId]').focus();
+			$('#chkSaveId').prop('checked', false);
+		} else {
+			$('#loginForm input[name=passwd]').focus();
+			$('#chkSaveId').prop('checked', true);
+		}
+	});
+/*]]>*/
+</script>
+
+</th:block>
+
+</body>
+</html>

+ 2 - 2
src/main/webapp/WEB-INF/views/web/common/error/500Web.html

@@ -23,13 +23,13 @@
 <body>
 
 <th:block th:fragment="content">
-	<div id="wrapper" layout:fragment="content">
+	<div id="wrapper">
 		<ul class="msgWrap">
 			<li class="title">죄송합니다. 서비스 이용이 원활하지 않습니다.</li>
 			<li class="cont" th:if="${message == null}">요청하신 페이지에 에러가 발생하였습니다. 서비스 이용에 불편을 끼쳐드려 죄송합니다.</li>
 			<li class="cont" th:if="${message != null && message != '' && message != 'null'}" th:text="${message}"></li>
 			<li class="button">
-				<button type="button" class="btn big white" onclick="cfnGoToPage(_PAGE_MAIN);">위비스몰</button>
+				<button type="button" class="btn big white" onclick="cfnGoToPage(_PAGE_MAIN);">스타일24몰</button>
 				<button type="button" class="btn big black marL10"  onclick="history.back(-1); return false;">이전페이지</button>
 			</li>
 		</ul>

+ 3 - 2
src/main/webapp/WEB-INF/views/web/common/fragments/GnbWeb.html

@@ -51,8 +51,9 @@
 				</a>
 			</div>
 			<div class="util_group">
-				<span><a href="mb_login.html" title="로그인 바로가기">로그인</a></span>
-				<span><a href="mb_join_1.html" title="회원가입 바로가기">회원가입</a></span>
+				<span th:if="${sessionInfo == null}"><a href="javascript:void(0);" onclick="cfnGoToPage(_PAGE_LOGIN);" title="로그인 바로가기">로그인</a></span>
+				<span th:if="${sessionInfo != null}"><a href="javascript:void(0);" onclick="cfnGoToPage(_PAGE_LOGOUT);" title="로그아웃">로그아웃</a></span>
+				<span th:if="${sessionInfo == null}"><a href="javascript:void(0);" onclick="cfnGoToPage(_PAGE_CUSTOMER_JOIN);" title="회원가입 바로가기">회원가입</a></span>
 				<span><a href="javascript:void(0);" onclick="cfnGoToPage(_PAGE_MYPAGE);" title="마이페이지 바로가기">마이페이지</a></span>
 			</div>
 		</div>

+ 1 - 0
src/main/webapp/WEB-INF/views/web/common/fragments/HeadWeb.html

@@ -33,6 +33,7 @@
 	<script src="/ux/pc/js/jquery-ui.js"></script>
 	<script src="/ux/pc/js/jquery.modal.min.js"></script>
 	<script src="/ux/plugins/jquery.serializeObject.min.js"></script>
+	<script src="/ux/plugins/mcxdialog/mcxdialog_ui.js"></script>
 
 	<!-- Global site tag (gtag.js) - Google Analytics -->
 <!-- 	<script async src="https://www.googletagmanager.com/gtag/js?id=UA-168660512-1"></script> -->

BIN
src/main/webapp/images/btn_top_close.png


BIN
src/main/webapp/images/pc/bg_coupon_code1.png


BIN
src/main/webapp/images/pc/btn_close_code.png


BIN
src/main/webapp/images/pc/cursor_zoom.png


BIN
src/main/webapp/images/pc/ico_admin.png


BIN
src/main/webapp/images/pc/ico_bracket.png


BIN
src/main/webapp/images/pc/ico_chk_rdi.png


BIN
src/main/webapp/images/pc/ico_chk_rdi_bak.png


BIN
src/main/webapp/images/pc/ico_close1.png


BIN
src/main/webapp/images/pc/ico_cp_down.png


BIN
src/main/webapp/images/pc/ico_dp_arrow.png


BIN
src/main/webapp/images/pc/ico_like2.png


BIN
src/main/webapp/images/pc/ico_myinfo_arrow.png


BIN
src/main/webapp/images/pc/ico_mysm_arrow.png


BIN
src/main/webapp/images/pc/ico_pop_cls02.png


BIN
src/main/webapp/images/pc/ico_saletag.png


BIN
src/main/webapp/images/pc/ico_star01.png


BIN
src/main/webapp/images/pc/ico_star02.png


BIN
src/main/webapp/images/pc/ico_timer.png


BIN
src/main/webapp/images/pc/ico_trash.png


BIN
src/main/webapp/images/pc/slide_next.png


BIN
src/main/webapp/images/pc/slide_prev.png


BIN
src/main/webapp/images/pc/star_empty.png


BIN
src/main/webapp/images/pc/thumb/attend_banner.jpg


BIN
src/main/webapp/images/pc/thumb/bigbanner_slide02.png


BIN
src/main/webapp/images/pc/thumb/comment_banner.jpg


BIN
src/main/webapp/images/pc/thumb/dp_exhibition_pr01.jpg


BIN
src/main/webapp/images/pc/thumb/dp_exhibition_pr02.jpg


BIN
src/main/webapp/images/pc/thumb/dp_exhibition_pr03.jpg


BIN
src/main/webapp/images/pc/thumb/dp_hd_img01.jpg


BIN
src/main/webapp/images/pc/thumb/dp_submain_img01.jpg


BIN
src/main/webapp/images/pc/thumb/dp_submain_img02.jpg


BIN
src/main/webapp/images/pc/thumb/dp_submain_img03.jpg


BIN
src/main/webapp/images/pc/thumb/dp_submain_img04.jpg


BIN
src/main/webapp/images/pc/thumb/ev_cmt_img02.jpg


BIN
src/main/webapp/images/pc/thumb/ev_cmt_img03.jpg


BIN
src/main/webapp/images/pc/thumb/renewal_banner.jpg


BIN
src/main/webapp/images/pc/thumb/tmp_cartColor1.jpg


BIN
src/main/webapp/images/pc/thumb/tmp_desc_bnr.jpg


BIN
src/main/webapp/images/pc/thumb/tmp_desc_mds.jpg


BIN
src/main/webapp/images/pc/thumb/tmp_detail_desc1.jpg


BIN
src/main/webapp/images/pc/thumb/tmp_detail_desc2.jpg


BIN
src/main/webapp/images/pc/thumb/tmp_fabric_desc1.jpg


BIN
src/main/webapp/images/pc/thumb/tmp_gift_empty.jpg


BIN
src/main/webapp/images/pc/thumb/tmp_label_desc1.jpg


BIN
src/main/webapp/images/pc/thumb/tmp_label_desc2.jpg


BIN
src/main/webapp/images/pc/thumb/tmp_outfit_desc1.jpg


BIN
src/main/webapp/images/pc/thumb/tmp_outfit_desc2.jpg


BIN
src/main/webapp/images/pc/thumb/tmp_outfit_desc3.jpg


BIN
src/main/webapp/images/pc/thumb/tmp_pdDetail7_1.jpg


BIN
src/main/webapp/images/pc/thumb/tmp_pdLookbook2.jpg


BIN
src/main/webapp/images/pc/thumb/tmp_pdLookbook3.jpg


BIN
src/main/webapp/images/pc/thumb/tmp_pdTogether1.jpg


+ 350 - 25
src/main/webapp/ux/pc/css/common.css

@@ -295,8 +295,8 @@ textarea {background-color:transparent; border:1px solid #d7d7d7; width:99%; ove
 .btn {
   display: inline-block;
   margin-bottom: 0;
-  padding: 14px 34px;
-  font-size: 14px;
+  padding: 13px 41px;
+  font-size: 16px;
   font-weight: 400;
   line-height: 20px;
   text-align: center;
@@ -429,10 +429,12 @@ background-color: #fe970a;border-color: #fe970a;color:#ffffff;
 .ico_trash::before {content: ""; width:13px; height:16px; background:url(/images/pc/ico_trash.png) no-repeat 50% 50%;}
 .ico_trash_wh::before {content: ""; width:13px; height:16px; background:url(/images/pc/ico_trash_white.png) no-repeat 50% 50%;}
 .ico_like::before {content: ""; width: 19px; height:16px;background: url(/images/pc/ico_like.png) no-repeat 0% 50%; background-size:cover;}
-.active .ico_like::before {background-position:100% 50%;}
+.ico_like2::before {content: ""; width: 16px; height:14px;background: url(/images/pc/ico_like2.png) no-repeat 0% 50%; background-size:cover;}
+.active .ico_like::before,
+.active .ico_like2::before {background-position:100% 50%;}
 .ico_star::before {content: ""; width: 17px; height:17px;background: url(/images/pc/ico_star.png) no-repeat 0% 50%; background-size:cover;}
 .active .ico_star::before {background-position:100% 50%;}
-.ico_saletag::before {content: ""; width:36px;height:16px;background: url(/images/pc/ico_saletag.png) no-repeat 50% 50%; background-size:cover;}
+.ico_saletag::before {content: ""; width:34px;height:17px;background: url(/images/pc/ico_saletag.png) no-repeat 50% 50%; background-size:cover;}
 .ico_calender::before {content: ""; width:15px;height:16px;background: url(/images/pc/ico_calender.png) no-repeat 50% 50%; background-size:cover;}
 .ico_snslogin::before {content: ""; background-image: url(/images/pc/ico_snslogin.png); background-size:auto 100%;}
 .ico_snslogin.kakao::before {width:20px; height:22px; background-position:0 0;}
@@ -444,6 +446,7 @@ background-color: #fe970a;border-color: #fe970a;color:#ffffff;
 .ico_check.gray::before {content: ""; background-position:0px -16px;}
 .ico_phone::before {content: ""; width:22px; height:30px; background:url(/images/pc/ico_join_bg.png) no-repeat 0 0; background-size:auto 100%;}
 .ico_ipin::before {content: ""; width:30px; height:30px; background:url(/images/pc/ico_join_bg.png) no-repeat -30px 0; background-size:auto auto;}
+.ico_close1::before {content: ""; width:12px;height:12px;background: url(/images/pc/ico_close1.png) no-repeat 50% 50%; background-size:cover;}
 
 /* btn linktext */
 a[class*="link"]::after, .btn_link span::after {
@@ -918,23 +921,23 @@ select,
 .form_field input[type="checkbox"]{ position:absolute; width:1px; height:1px; padding:0; margin:-1px; overflow:hidden; clip:rect(0,0,0,0); border:0; } 
 .form_field input[type="checkbox"] + label{ display:inline-block; position:relative; padding-left:26px; cursor:pointer; font-size: 14px; line-height: 1.5;font-weight: 300;letter-spacing: 0;} 
 .form_field input[type="checkbox"] + label:before{ 
-  content:''; position:absolute; left:0; top:3px; width:18px; height:18px; text-align:center; background:#fff; border:1px solid #ccc; border-radius: 100%; box-sizing:border-box; 
+  content:''; position:absolute; left:0; top:3px; width:20px; height:20px; text-align:center; background:#fff; /*border:1px solid #ccc;*/ border-radius: 100%; box-sizing:border-box; 
   background: url('/images/pc/ico_chk_rdi.png') no-repeat;
-  background-position: -1px -2px;
+  background-position: 0px 0px;
 } 
 .form_field input[type="checkbox"]:Disabled + label, 
 .form_field input[type="radio"]:Disabled + label{cursor: default;opacity: .45;} 
 
 .form_field input[type="checkbox"]:checked + label:after{ 
-  content: ''; position:absolute; top:3px; left:0; width:18px; height:18px; background-color: #fd4800; 
+  content: ''; position:absolute; top:3px; left:0; width:20px; height:20px; background-color: #fd4800; 
   background: url('/images/pc/ico_chk_rdi.png') no-repeat;
-  background-position: -21px -1px;
+  background-position: -20px 0px;
 }
 
 .form_field input[type="checkbox"]:Disabled + label:after{ 
-  content: ''; position:absolute; top:3px; left:0; width:18px; height:18px; background-color: #fd4800; 
+  content: ''; position:absolute; top:3px; left:0; width:20px; height:20px; background-color: #fd4800; 
   background: url('/images/pc/ico_chk_rdi.png') no-repeat;
-  background-position: 0px -1px;
+  background-position: -40px 0px;
   /* background-position: -42px -1px; */
 }
 
@@ -947,22 +950,22 @@ select,
 .form_field input[type="radio"]{ position:absolute; width:1px; height:1px; padding:0; margin:-1px; overflow:hidden; clip:rect(0,0,0,0); border:0; } 
 .form_field input[type="radio"] + label{ display:inline-block; position:relative; padding-left:26px; cursor:pointer; font-size: 16px;line-height: 1.5;font-weight: 300;letter-spacing: 0;} 
 .form_field input[type="radio"] + label:before{ 
-  content:''; position:absolute; left:0; top:3px; width:20px; height:20px; text-align:center; background:#fff; border:1px solid #ccc; border-radius: 100%; box-sizing:border-box; 
+  content:''; position:absolute; left:0; top:3px; width:20px; height:20px; text-align:center; background:#fff; /*border:1px solid #ccc;*/ border-radius: 100%; box-sizing:border-box; 
   background: url('/images/pc/ico_chk_rdi.png') no-repeat;
-  background-position: -64px -1px;
+  background-position: -60px 0px;
 } 
 
 /* 보여질 부분의 스타일을 추가하면 된다. */ 
 .form_field input[type="radio"]:checked + label:after{ 
   content: ''; position:absolute; top:3px; left:0; width:20px; height:20px; background-color: #fd4800; 
   background: url('/images/pc/ico_chk_rdi.png') no-repeat;
-  background-position: -84px 0px;
+  background-position: -80px 0px;
 }
 
 .form_field input[type="radio"]:Disabled + label:after{ 
   content: ''; position:absolute; top:3px; left:0; width:20px; height:20px; background-color: #fd4800; 
   background: url('/images/pc/ico_chk_rdi.png') no-repeat;
-  background-position: -105px 0px;
+  background-position: -100px 0px;
 }
 
 
@@ -1061,13 +1064,15 @@ input[type="file"] {
 
 /* header */
 #header {-webkit-transition:all .3s ease-in-out;transition:all .3s ease-in-out;} 
+#header .common_header .nav > ul.btn_home {display:none;}
 #header.minify {position: fixed; top:0; left:0; right:0; z-index:100;}
 #header.minify .common_header .hd_top_banner {display:none;}
 #header.minify .common_header > .area {height:auto; padding:20px 40px 10px}
-#header.minify .common_header > .gnb {height:auto; padding:10px 40px 20px}
+#header.minify .common_header > .gnb {height:auto; padding:30px 40px 30px}
 #header.minify .common_header .logo {margin-top:0}
 #header.minify .common_header .logo .ico_logo:before {width:118px; height:18px}
 #header.minify .common_header .util_group {margin-top:2px}
+#header.minify .common_header .nav > ul.btn_home {display:inline-block;}
 #header.minify .common_header .nav > ul > li > a {font-size:17px}
 #header.minify .common_header .search > .area {width:300px; border-bottom-width:1px;}
 #header.minify .common_header .search .search_input {font-size:15px;}
@@ -1363,15 +1368,6 @@ input[type="file"] {
 
 
 
-
-
-
-
-
-
-
-
-
 /* slide custom */
 .slick-dots {position: absolute;bottom: 25px;display: block;width: 100%;padding: 0;margin: 0;list-style: none;text-align: center;
 }
@@ -1384,7 +1380,7 @@ color: transparent;border: 0;outline: none;background: transparent; background:
 /* End of slide custom */
 
 
-/* Alert Custom */
+/* Mesage, Toast, Alert Custom */
 .alert {
 	padding: 15px;border: 1px solid transparent; border-radius: 4px;margin-bottom: 10px;line-height: 21px;
 	background-color: #dddddd;color: #666666;border-color: #dddddd;
@@ -1394,6 +1390,335 @@ button.alertCls {-webkit-appearance: none;padding: 0;cursor: pointer;background:
 .alertCls:hover, .alertCls:focus {color: #000;text-decoration: none;cursor: pointer;filter: alpha(opacity=50);opacity: .5;}
 
 
+/* ALERT, CONFIRM Plugin custom  */
+.dialog-mobile-bg {
+	position: fixed;
+	top: 0;
+	left: 0;
+	z-index: 19;
+	width: 100%;
+	height: 100%;
+	background-color: rgba(0, 0, 0, 0.3);
+	-ms-transform: translate3d(0, 0, 0);
+	-webkit-transform: translate3d(0, 0, 0);
+	transform: translate3d(0, 0, 0);
+}
+/*alert confirm*/
+.dialog-mobile {
+	padding: 0 40px 40px 40px;
+	text-align:center;
+	position: fixed;
+	top: 50%;
+	left: 0;
+	z-index: 20;
+	min-width:200px;
+	background-color: #FFFFFF;
+	border-radius: 0px;
+	-ms-transform: translate3d(0, 0, 0);
+	-webkit-transform: translate3d(0, 0, 0);
+	transform: translate3d(0, 0, 0);
+}
+.dialog-mobile .dialog-title {
+    padding: 0.8em 1em 0.5em;
+    text-align: center;
+    color: #333333;
+	font-size: 18px;
+    font-weight: 500;
+    border-radius: 5px 5px 0 0;
+}
+.dialog-mobile .dialog-content {
+	position: relative;
+	padding:50px 0 40px 0;
+	line-height: 2em;
+	text-align: left;
+	color: #000;
+	font-size:15px;
+	text-align:center;
+}
+.dialog-mobile .dialog-content em {
+	color:#df6400
+}
+.dialog-mobile .dialog-button,
+.dialog-mobile .dialog-sure-button,
+.dialog-mobile .dialog-cancel-button {
+	display:inline-block;
+	position: relative;
+	margin:0 5px;
+	padding:0 30px;
+	min-width: 70px;
+	height: 38px;
+	line-height: 38px;
+	text-align: center;
+	font-size:14px;
+	cursor:pointer;
+	border-radius:0px;
+}
+.dialog-mobile .dialog-button{
+	color: #fff;
+	background:#000;
+	border:1px solid #000;
+	min-width:100px;
+}
+.dialog-mobile .dialog-cancel-button {
+	color: #000;
+	background: #fff;
+	border:1px solid #999;
+	min-width:100px;
+}
+.dialog-mobile .dialog-sure-button{
+	color: #fff;
+	background:#000;
+	border:1px solid #000;
+	min-width:100px;
+}
+.dialog-mobile button[i='1']{
+	color: #000 !important;
+	background:#fff !important;
+	border:1px solid #777;
+	min-width:100px;
+}
+
+/* 닫기 아이콘 */
+.dialog-close-btn {
+	position:absolute;
+	top:0;
+	right:0;
+	padding:20px;
+	width: 17px;
+	height: 17px;
+	cursor:pointer;
+	background:url('/images/btn_top_close.png') no-repeat 50% 50%;
+}
+
+/*bottom dialog*/
+.dialog-mobile-bottom {
+	position: fixed;
+	left: 0;
+	bottom: 0;
+	z-index: 10001;
+	width: 100%;
+	color: #333333;
+	background-color: #EEEEEE;
+}
+.dialog-mobile-bottom .bottom-btn-item {
+	text-align: center;
+}
+.bottom-btn-item .dialog-item-btn {
+	background: #FFFFFF;
+	padding: 0.5em 0;
+	border-bottom: 1px solid #EEEEEE;
+}
+.bottom-btn-item .dialog-item-btn:last-child {
+	border-bottom: none;
+}
+.dialog-mobile-bottom .dialog-cancel-btn {
+	margin-top: 0.6em;
+	text-align: center;
+	background: #FFFFFF;
+	padding: 0.5em 0;
+}
+/*toast*/
+.dialog-mobile-toast {
+	position: fixed;
+	bottom: 5em;
+}
+.dialog-mobile-toast .toast-content {
+	padding: 0.5em 1em;
+	color: #FFFFFF;
+	border-radius: 2px;
+	background-color: #333333;
+}
+/*loading*/
+.mobile-loading-bg {
+	position: fixed;
+	top: 0;
+	left: 0;
+	z-index: 10000;
+	width: 100%;
+	height: 100%;
+	background-color: rgba(0, 0, 0, 0.3);
+	-webkit-transform: translate3d(0, 0, 0);
+	transform: translate3d(0, 0, 0);
+}
+.mobile-loading {
+	position: fixed;
+	top: 0;
+	left: 0;
+	z-index: 10001;
+	min-width: 2em;
+	min-height: 2em;
+	padding: 0.8em 1.6em;
+	text-align: center;
+	border-radius: 2px;
+	color: #FFFFF0;
+	background-color: #0A0A0A;
+	-webkit-transform: translate3d(0, 0, 0);
+	transform: translate3d(0, 0, 0);
+}
+/*animation*/
+.animation-zoom-in, .animation-zoom-out,
+.animation-bottom-in, .animation-bottom-out,
+.animation-bg-fadeIn {
+	-webkit-animation-duration: 0.3s;
+	-webkit-animation-fill-mode: both;
+	animation-duration: 0.3s;
+	animation-fill-mode: both;
+}
+.animation-fade-in, .animation-fade-out {
+	-webkit-animation-duration: 1s;
+	-webkit-animation-timing-function: ease-out;
+	-webkit-animation-fill-mode: both;
+	animation-duration: 1s;
+	animation-timing-function: ease-out;
+	animation-fill-mode: both;
+}
+.animation-zoom-in {
+	-webkit-animation-name: zoomIn;
+	animation-name: zoomIn;
+}
+.animation-zoom-out {
+	-webkit-animation-name: zoomOut;
+	animation-name: zoomOut;
+}
+.animation-fade-in {
+	-webkit-animation-name: fadeIn;
+	animation-name: fadeIn;
+}
+.animation-fade-out {
+	-webkit-animation-name: fadeOut;
+	animation-name: fadeOut;
+}
+.animation-bottom-in {
+	-webkit-animation-name: bottomIn;
+	animation-name: bottomIn;
+}
+.animation-bottom-out {
+	-webkit-animation-name: bottomOut;
+	animation-name: bottomOut;
+}
+.animation-bg-fadeIn {
+	-webkit-animation-name: fadeIn;
+	animation-name: fadeIn;
+}
+
+@-webkit-keyframes zoomIn {
+	from{
+		opacity: 0;
+		-webkit-transform: scale(0, 0);
+	}
+	to{
+		opacity: 1;
+		-webkit-transform: scale(1, 1);
+	}
+}
+@-webkit-keyframes zoomOut {
+	from{
+		opacity: 1;
+		-webkit-transform: scale(1, 1);
+	}
+	90%{
+		-webkit-transform: scale(0.3, 0.3);
+	}
+	to{
+		opacity: 0;
+		-webkit-transform: scale(0, 0);
+	}
+}
+@keyframes zoomIn {
+	from{
+		opacity: 0;
+		transform: scale(0, 0);
+	}
+	to{
+		opacity: 1;
+		transform: scale(1, 1);
+	}
+}
+@keyframes zoomOut {
+	from{
+		opacity: 1;
+		transform: scale(1, 1);
+	}
+	90%{
+		transform: scale(0.3, 0.3);
+	}
+	to{
+		opacity: 0;
+		transform: scale(0, 0);
+	}
+}
+@-webkit-keyframes fadeIn {
+	from{
+		opacity: 0;
+	}
+	to{
+		opacity: 1;
+	}
+}
+@-webkit-keyframes fadeOut {
+	from{
+		opacity: 1;
+	}
+	30%{
+		opacity: 0.3;
+	}
+	to{
+		opacity: 0;
+	}
+}
+@keyframes fadeIn {
+	from{
+		opacity: 0;
+	}
+	to{
+		opacity: 1;
+	}
+}
+@keyframes fadeOut {
+	from{
+		opacity: 1;
+	}
+	30%{
+		opacity: 0.3;
+	}
+	to{
+		opacity: 0;
+	}
+}
+@-webkit-keyframes bottomIn {
+	from{
+		bottom: -1000px;
+	}
+	to{
+		bottom: 0;
+	}
+}
+@-webkit-keyframes bottomOut {
+	from{
+		bottom: 0;
+	}
+	to{
+		bottom: -1000px;
+	}
+}
+@keyframes bottomIn {
+	from{
+		bottom: -1000px;
+	}
+	to{
+		bottom: 0;
+	}
+}
+@keyframes bottomOut {
+	from{
+		bottom: 0;
+	}
+	to{
+		bottom: -1000px;
+	}
+}
+
+
 /*  modal popup  */
 .blocker{position:fixed;top:0;right:0;bottom:0;left:0;width:100%;height:100%;overflow:auto;z-index:999999;padding:0px;box-sizing:border-box;background-color:#000;background-color:rgba(0,0,0,0.75);text-align:center;}
 .blocker:before{content:"";display:inline-block;height:100%;vertical-align:middle;margin-right:-0.05em;}

+ 376 - 0
src/main/webapp/ux/plugins/mcxdialog/mcxdialog_ui.js

@@ -0,0 +1,376 @@
+/**
+ * Mcx Dialog Mobile v0.1.0
+ * Copyright (C) 2018 mcx
+ * https://github.com/code-mcx/mcx-dialog-mobile
+ */
+(function (global, factory) {
+		typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
+			typeof define === 'function' && define.amd ? define(factory) :
+			(global.mcxDialog = factory());
+	}
+	(this, (function () {
+			'use strict';
+
+			function addClass(e, c) {
+				var newclass = e.className.split(" ");
+				if (e.className === "") newclass = [];
+				newclass.push(c);
+				e.className = newclass.join(" ");
+			};
+
+			function extend(source, target) {
+				for (var key in target) {
+					source[key] = target[key];
+				}
+				return source;
+			};
+
+			function getAnimationEndName(dom) {
+				var cssAnimation = ["animation", "webkitAnimation"];
+				var animationEnd = {
+					"animation": "animationend",
+					"webkitAnimation": "webkitAnimationEnd"
+				};
+				for (var i = 0; i < cssAnimation.length; i++) {
+					if (dom.style[cssAnimation[i]] != undefined) {
+						return animationEnd[cssAnimation[i]];
+					}
+				}
+				return undefined;
+			};
+
+			function getFontSize() {
+				var clientWidth = document.documentElement.clientWidth;
+				if (clientWidth < 640) return 16 * (clientWidth / 375) + "px";
+				else return 16;
+			};
+
+			var layer = {
+
+				initOpen: function initOpen(dom, options) {
+
+					dom.style.fontSize = getFontSize();
+					var body = document.querySelector("body");
+					var bg = document.createElement("div");
+					addClass(bg, "dialog-mobile-bg");
+					if (options.showBottom == true) {
+						addClass(bg, "animation-bg-fadeIn");
+					}
+					if (options.bottom) {
+						bg.addEventListener("click", function () {
+							handleClose();
+						});
+					}
+					body.appendChild(bg);
+					body.appendChild(dom);
+
+					var animationEndName = getAnimationEndName(dom);
+
+					function handleClose() {
+						if (animationEndName) {
+							layer.close([bg]);
+							addClass(dom, options.closeAnimation);
+							dom.addEventListener(animationEndName, function () {
+								layer.close([dom]);
+							});
+						} else {
+							layer.close([bg, dom]);
+						}
+					};
+
+					//상단 닫기 아이콘
+					var closeBtn = document.querySelector(".dialog-close-btn");
+					closeBtn.addEventListener("click", function () {
+						handleClose();
+					});
+					closeBtn.focus(); 	/* 200811 박성희 추가  */
+
+					//set button click event
+					options.btns.forEach(function (btn, i) {
+						if (options.alertCBtn) { //alertC
+							btn.addEventListener("click", function () {
+								handleClose();
+								options.sureBtnClick();
+
+							});
+						} else if (options.confirmCBtn || options.bottom) { //confirmC or bottom
+							btn.addEventListener("click", function () {
+								handleClose();
+								options.btnClick(this.getAttribute("i"));
+							});
+						} else {
+							if (i != 0) { //confirm
+								btn.addEventListener("click", function () {
+									handleClose();
+									options.sureBtnClick();
+								});
+							} else { //alert
+								btn.addEventListener("click", handleClose);
+							}
+						}
+					});
+
+
+
+
+
+					if (!options.bottom) {
+						//set position
+						dom.style.top = (document.documentElement.clientHeight - dom.offsetHeight) / 2 + "px";
+						dom.style.left = (document.documentElement.clientWidth - dom.offsetWidth) / 2 + "px";
+					}
+
+
+				},
+
+				close: function close(doms) {
+					var body = document.querySelector("body");
+					for (var i = 0; i < doms.length; i++) {
+						body.removeChild(doms[i]);
+					}
+
+				}
+
+			};
+
+
+			var mcxDialog = {
+				//alert ------------------------
+				alert: function alert(content) {
+					var btn = document.createElement("button"); /* 200811 박성희 */
+					btn.setAttribute("type", "button");	/* 200811 박성희 */
+					btn.innerText = "확인";
+					addClass(btn, "dialog-button");
+
+					var opts = {};
+					opts.btns = [btn];
+
+					this.open(content, opts);
+				},
+
+				//alertC ------------------------
+				alertC: function confirm(content, options) {
+					var opts = {
+						sureBtnText: "확인",
+						sureBtnClick: function sureBtnClick() {}
+					};
+					opts = extend(opts, options);
+
+					var sureBtn = document.createElement("button");  /* 200811 박성희 */
+					sureBtn.setAttribute("type", "button"); /* 200811 박성희 */
+					sureBtn.innerText = opts.sureBtnText;
+					addClass(sureBtn, "dialog-sure-button");
+					opts.alertCBtn = true;
+
+					opts.btns = [sureBtn];
+					this.open(content, opts);
+
+				},
+
+				//confirm ------------------------
+				confirm: function confirm(content, options) {
+					var opts = {
+						cancelBtnText: "취소",
+						sureBtnText: "확인",
+						sureBtnClick: function sureBtnClick() {}
+					};
+					opts = extend(opts, options);
+
+					var cancelBtn = document.createElement("button"); /* 200811 박성희 */
+					cancelBtn.setAttribute("type", "button"); /* 200811 박성희 */
+					cancelBtn.innerText = opts.cancelBtnText; /* 200811 박성희 */
+					addClass(cancelBtn, "dialog-cancel-button");
+
+					var sureBtn = document.createElement("button"); /* 200811 박성희 */
+					sureBtn.setAttribute("type", "button"); /* 200811 박성희 */
+					sureBtn.innerText = opts.sureBtnText;
+					addClass(sureBtn, "dialog-sure-button");
+
+					opts.btns = [cancelBtn, sureBtn];
+					this.open(content, opts);
+				},
+
+				//confirmC ------------------------
+				confirmC: function confirmC(content, options) {
+					var opts = {
+						btn: ["확인"],
+						btnClick: function btnClick(index) {}
+					};
+					opts = extend(opts, options);
+
+					var dialog = document.createElement("div");
+					var dialogContent = document.createElement("div");
+					var closeBtn = document.createElement("button"); /* 200811 박성희 */
+					closeBtn.setAttribute("type", "button"); /* 200811 박성희 */
+
+					addClass(dialog, "dialog-mobile");
+					addClass(dialog, "animation-zoom-in");
+					addClass(dialogContent, "dialog-content");
+					addClass(closeBtn, "dialog-close-btn");
+
+					dialogContent.innerHTML = content;
+					dialog.appendChild(dialogContent);
+					dialog.appendChild(closeBtn);
+
+					opts.btns = [];
+					opts.btns.push(closeBtn);
+					opts.btn.forEach(function (b, i) {
+						var btn = document.createElement("button"); /* 200811 박성희 */
+						btn.setAttribute("type", "button"); /* 200811 박성희 */
+						btn.innerText = opts.btn[i];
+						btn.setAttribute("i", i + 1);
+						addClass(btn, "dialog-sure-button");
+						dialog.appendChild(btn);
+						opts.btns.push(btn);
+					});
+					opts.closeAnimation = "animation-zoom-out";
+					opts.confirmCBtn = true;
+
+					layer.initOpen(dialog, opts);
+				},
+
+				open: function open(content, options) {
+					var dialog = document.createElement("div");
+					var dialogContent = document.createElement("div");
+					var closeBtn = document.createElement("button"); //상단 닫기버튼  /* 200811 박성희 */
+					closeBtn.setAttribute("type", "button");  /* 200811 박성희 */
+
+
+					addClass(dialog, "dialog-mobile");
+					addClass(dialog, "animation-zoom-in");
+					addClass(dialogContent, "dialog-content");
+					addClass(closeBtn, "dialog-close-btn"); //상단 닫기버튼
+
+					dialogContent.innerHTML = content;
+					dialog.appendChild(dialogContent);
+					dialog.appendChild(closeBtn); //상단 닫기버튼
+					options.btns.forEach(function (btn, i) {
+						dialog.appendChild(btn);
+					});
+					options.closeAnimation = "animation-zoom-out";
+
+					layer.initOpen(dialog, options);
+
+				},
+
+
+				showBottom: function showBottom(options) {
+					var opts = {
+						btn: ["확인"],
+						btnColor: [],
+						btnClick: function btnClick(index) {}
+					};
+					opts = extend(opts, options);
+					opts.bottom = true;
+
+					var bottomDialog = document.createElement("div");
+					var dialogItem = document.createElement("div");
+					var closeBtn = document.createElement("button"); //상단 닫기버튼  /* 200811 박성희 */
+					closeBtn.setAttribute("type", "button"); /* 200811 박성희 */
+					var cancelBtn = document.createElement("button");  /* 200811 박성희 */
+					cancelBtn.setAttribute("type", "button"); /* 200811 박성희 */
+
+					cancelBtn.innerText = "취소";
+					addClass(bottomDialog, "dialog-mobile-bottom");
+					addClass(bottomDialog, "animation-bottom-in");
+					addClass(dialogItem, "bottom-btn-item");
+					addClass(closeBtn, "dialog-close-btn"); //상단 닫기버튼
+					addClass(cancelBtn, "dialog-cancel-btn");
+
+					bottomDialog.appendChild(dialogItem);
+					bottomDialog.appendChild(closeBtn); //상단 닫기버튼
+					bottomDialog.appendChild(cancelBtn);
+
+					opts.btns = [];
+					opts.btns.push(closeBtn);
+					opts.btns.push(cancelBtn);
+					opts.btn.forEach(function (b, i) {
+						var btn = document.createElement("button");  /* 200811 박성희 */
+						btn.setAttribute("type", "button");	 /* 200811 박성희 */
+						btn.innerText = opts.btn[i];
+						btn.setAttribute("i", i + 1);
+						addClass(btn, "dialog-item-btn");
+						if (opts.btnColor[i]) btn.style.color = opts.btnColor[i];
+						dialogItem.appendChild(btn);
+						opts.btns.push(btn);
+					});
+					opts.closeAnimation = "animation-bottom-out";
+					opts.showBottom = true;
+
+					layer.initOpen(bottomDialog, opts);
+				},
+				toast: function toast(content, time) {
+					time = time || 3;
+					var toast = document.createElement("div");
+					var toastContent = document.createElement("div");
+
+					addClass(toast, "dialog-mobile-toast");
+					addClass(toast, "animation-fade-in");
+					addClass(toastContent, "toast-content");
+
+					toastContent.innerText = content;
+
+					toast.appendChild(toastContent);
+
+					var body = document.querySelector("body");
+					body.appendChild(toast);
+
+					toast.style.fontSize = getFontSize();
+					toast.style.left = (document.documentElement.clientWidth - toast.offsetWidth) / 2 + "px";
+
+					setTimeout(function () {
+						body.removeChild(toast);
+					}, time * 300);
+				},
+
+				loadElement: [],
+				loading: function loading(options) {
+					var opts = {
+						src: "img",
+						hint: ""
+					};
+					opts = extend(opts, options);
+
+					var loadingBg = document.createElement("div");
+					var loading = document.createElement("div");
+					var img = document.createElement("img");
+
+					addClass(loadingBg, "mobile-loading-bg");
+					addClass(loading, "mobile-loading");
+					addClass(loading, "animation-zoom-in");
+					img.src = opts.src + "/loading.gif";
+					loading.appendChild(img);
+
+					if (opts.hint) {
+						var loadingContent = document.createElement("div");
+						addClass(loadingContent, "loading-content");
+						loadingContent.innerText = opts.hint;
+						loading.appendChild(loadingContent);
+					}
+
+					var body = document.querySelector("body");
+					body.appendChild(loadingBg);
+					body.appendChild(loading);
+
+					loading.style.fontSize = getFontSize();
+					loading.style.left = (document.documentElement.clientWidth - loading.offsetWidth) / 2 + "px";
+					loading.style.top = (document.documentElement.clientHeight - loading.offsetHeight) / 2 + "px";
+
+					this.loadElement.push(loadingBg);
+					this.loadElement.push(loading);
+				},
+				closeLoading: function closeLoading() {
+					layer.close(this.loadElement);
+					this.loadElement = [];
+				}
+			};
+
+			// providing better operations in Vue
+			mcxDialog.install = function (Vue, options) {
+				Vue.prototype.$mcxDialog = mcxDialog;
+			};
+
+
+			return mcxDialog;
+
+})));

+ 9 - 2
src/main/webapp/ux/style24_link.js

@@ -1,13 +1,20 @@
 /*
  * Common URL Definition
  */
-const _PAGE_LOGIN = "/signin";	// GNB > 로그인
-const _PAGE_LOGOUT = "/logout";	// GNB > 로그아웃
+const _PAGE_LOGIN = _frontUrl + "/signin";	// GNB > 로그인
+const _PAGE_LOGOUT = _frontUrl + "/logout";	// GNB > 로그아웃
 
 //== 메인 ==/
 const _PAGE_MAIN = _frontUrl + "/display/mall/main/form";	// 몰메인
 
 //== 고객 ==/
+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";	// 고객 > 비밀번호 찾기 > 결과페이지
 
 //== 상품상세 ==/