Explorar o código

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

jsh77b %!s(int64=5) %!d(string=hai) anos
pai
achega
ef6995cca2
Modificáronse 50 ficheiros con 3711 adicións e 924 borrados
  1. 8 1
      pom.xml
  2. 3 4
      src/main/java/com/style24/front/biz/dao/TsfCartDao.java
  3. 17 0
      src/main/java/com/style24/front/biz/dao/TsfCouponDao.java
  4. 1 0
      src/main/java/com/style24/front/biz/dao/TsfCustomerDao.java
  5. 8 0
      src/main/java/com/style24/front/biz/dao/TsfLoginDao.java
  6. 73 0
      src/main/java/com/style24/front/biz/dao/TsfOrderDao.java
  7. 10 9
      src/main/java/com/style24/front/biz/service/TsfCartService.java
  8. 186 0
      src/main/java/com/style24/front/biz/service/TsfCouponService.java
  9. 47 0
      src/main/java/com/style24/front/biz/service/TsfCustomerService.java
  10. 20 6
      src/main/java/com/style24/front/biz/service/TsfLoginService.java
  11. 188 0
      src/main/java/com/style24/front/biz/service/TsfOrderService.java
  12. 257 39
      src/main/java/com/style24/front/biz/thirdparty/NiceCertify.java
  13. 54 1
      src/main/java/com/style24/front/biz/web/TsfCartController.java
  14. 328 14
      src/main/java/com/style24/front/biz/web/TsfCustomerController.java
  15. 140 17
      src/main/java/com/style24/front/biz/web/TsfMypageController.java
  16. 3 0
      src/main/java/com/style24/front/support/env/TsfConstants.java
  17. 2 18
      src/main/java/com/style24/front/support/security/TsfAuthenticationProvider.java
  18. 10 7
      src/main/java/com/style24/front/support/security/handler/TsfLoginFailureHandler.java
  19. 2 5
      src/main/java/com/style24/front/support/security/handler/TsfLoginSuccessHandler.java
  20. 2 5
      src/main/java/com/style24/front/support/security/handler/TsfRememberMeSuccessHandler.java
  21. 8 0
      src/main/java/com/style24/persistence/domain/Cart.java
  22. 35 0
      src/main/java/com/style24/persistence/domain/Coupon.java
  23. 1 0
      src/main/java/com/style24/persistence/domain/Login.java
  24. 38 2
      src/main/java/com/style24/persistence/mybatis/shop/TsfCoupon.xml
  25. 6 2
      src/main/java/com/style24/persistence/mybatis/shop/TsfCustomer.xml
  26. 26 12
      src/main/java/com/style24/persistence/mybatis/shop/TsfLogin.xml
  27. 290 0
      src/main/java/com/style24/persistence/mybatis/shop/TsfOrder.xml
  28. 12 6
      src/main/resources/config/application-locd.yml
  29. 4 0
      src/main/resources/config/application.yml
  30. 1 0
      src/main/resources/i18n/messages/message_ko_KR.properties
  31. BIN=BIN
      src/main/webapp/WEB-INF/lib/IPIN2Client.jar
  32. 54 23
      src/main/webapp/WEB-INF/views/web/SigninFormWeb.html
  33. 68 16
      src/main/webapp/WEB-INF/views/web/cart/cartListAjaxFormWeb.html
  34. 1 0
      src/main/webapp/WEB-INF/views/web/cart/cartListFormWeb.html
  35. 2 0
      src/main/webapp/WEB-INF/views/web/common/fragments/HeadWeb.html
  36. 0 399
      src/main/webapp/WEB-INF/views/web/customer/FindIdAndPwdFormWeb.html
  37. 0 96
      src/main/webapp/WEB-INF/views/web/customer/FindIdResultFormWeb.html
  38. 0 105
      src/main/webapp/WEB-INF/views/web/customer/FindPwdResultFormWeb.html
  39. 333 0
      src/main/webapp/WEB-INF/views/web/customer/IdFindFormWeb.html
  40. 70 28
      src/main/webapp/WEB-INF/views/web/customer/JoinFormWeb.html
  41. 30 0
      src/main/webapp/WEB-INF/views/web/customer/NiceCallbackFormWeb.html
  42. 37 0
      src/main/webapp/WEB-INF/views/web/customer/NiceCellPhoneFormWeb.html
  43. 39 0
      src/main/webapp/WEB-INF/views/web/customer/NiceIpinFormWeb.html
  44. 247 0
      src/main/webapp/WEB-INF/views/web/customer/PasswordChangeFormWeb.html
  45. 307 0
      src/main/webapp/WEB-INF/views/web/customer/PasswordFindFormWeb.html
  46. 398 0
      src/main/webapp/WEB-INF/views/web/mypage/MypageOrderDetailFormWeb.html
  47. 45 100
      src/main/webapp/WEB-INF/views/web/mypage/MypageOrderListFormWeb.html
  48. 228 0
      src/main/webapp/ux/customer/customer.js
  49. 1 1
      src/main/webapp/ux/plugins/gaga/gaga.validation.js
  50. 71 8
      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>
 	

+ 3 - 4
src/main/java/com/style24/front/biz/dao/TsfCartDao.java

@@ -1,13 +1,12 @@
 package com.style24.front.biz.dao;
 
+import java.util.Collection;
+import java.util.List;
+
 import com.style24.core.support.annotation.ShopDs;
 import com.style24.persistence.domain.Cart;
-import com.style24.persistence.domain.GoodsStock;
 import com.style24.persistence.domain.Order;
 
-import java.util.Collection;
-import java.util.List;
-
 /**
  * 장바구니 Dao
  * 

+ 17 - 0
src/main/java/com/style24/front/biz/dao/TsfCouponDao.java

@@ -1,6 +1,8 @@
 package com.style24.front.biz.dao;
 
 import com.style24.core.support.annotation.ShopDs;
+import com.style24.persistence.domain.Cart;
+import com.style24.persistence.domain.Coupon;
 
 /**
  * 쿠폰 Dao
@@ -11,4 +13,19 @@ import com.style24.core.support.annotation.ShopDs;
 @ShopDs
 public interface TsfCouponDao {
 
+	/**
+	 * 시리얼 쿠폰 지급 정보 조회
+	 * @param param
+	 * @author xodud1202
+	 * @since 2021. 02. 16
+	 */
+	Coupon getSerialCpnUseInfo(Coupon param);
+
+	/**
+	 * 입력된 시리얼 쿠폰 정보 조회
+	 * @param param
+	 * @author xodud1202
+	 * @since 2021. 02. 17
+	 */
+	Coupon getSearchSerialCpnInfo(Coupon param);
 }

+ 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 - 고객번호

+ 73 - 0
src/main/java/com/style24/front/biz/dao/TsfOrderDao.java

@@ -1,6 +1,9 @@
 package com.style24.front.biz.dao;
 
+import java.util.Collection;
+
 import com.style24.core.support.annotation.ShopDs;
+import com.style24.persistence.domain.Order;
 
 /**
  * 주문 Dao
@@ -11,4 +14,74 @@ import com.style24.core.support.annotation.ShopDs;
 @ShopDs
 public interface TsfOrderDao {
 
+	/**
+	 * 마이페이지 주문 정보 조회
+	 *
+	 * @param Order
+	 * @return Collection<Order>
+	 * @author card007
+	 * @since 2021. 02. 04
+	 */
+	Collection<Order> getOrderListForMypage(Order order);
+
+	/**
+	 * 마이페이지 주문상태 별 주문수량 조회
+	 *
+	 * @param Order
+	 * @return int
+	 * @author card007
+	 * @since 2021. 02. 08
+	 */
+	int getOrderStatCount(Order order);
+
+	/**
+	 * 마이페이지 주문변경상태 별 주문수량 조회
+	 *
+	 * @param Order
+	 * @return int
+	 * @author card007
+	 * @since 2021. 02. 08
+	 */
+	int getOrderChangeStatCount(Order order);
+
+	/**
+	 * 마이페이지 주문상세 금액정보 조회
+	 *
+	 * @param Order
+	 * @return Order
+	 * @author card007
+	 * @since 2021. 02. 15
+	 */
+	Order getOrderAmtForMypage(Order order);
+
+	/**
+	 * 마이페이지 주문상세 결제정보 조회
+	 *
+	 * @param Order
+	 * @return Order
+	 * @author card007
+	 * @since 2021. 02. 15
+	 */
+	Order getPaymentInfoForMypage(Order order);
+
+	/**
+	 * 마이페이지 주문상세 배송지 정보 조회
+	 *
+	 * @param Order
+	 * @return Order
+	 * @author card007
+	 * @since 2021. 02. 15
+	 */
+	Order getOrderDeliveryAddrInfo(Order order);
+
+	/**
+	 * 마이페이지 주문상세 주문내역삭제 처리
+	 *
+	 * @param Order
+	 * @return int
+	 * @author card007
+	 * @since 2021. 02. 17
+	 */
+	int updateOrderDisplayYn(Order order);
+
 }

+ 10 - 9
src/main/java/com/style24/front/biz/service/TsfCartService.java

@@ -18,6 +18,7 @@ import com.style24.core.support.session.TscSession;
 import com.style24.front.biz.dao.TsfCartDao;
 import com.style24.front.support.security.session.TsfSession;
 import com.style24.persistence.domain.Cart;
+import com.style24.persistence.domain.Coupon;
 import com.style24.persistence.domain.Goods;
 import com.style24.persistence.domain.GoodsStock;
 import com.style24.persistence.domain.Order;
@@ -114,9 +115,9 @@ public class TsfCartService {
 		StringBuilder sb = new StringBuilder();
 
 		// TODO 로그인 정보 세팅
-		cart.setRegNo(0);
-		cart.setCustNo(0);
-		cart.setUpdNo(0);
+		cart.setRegNo(1000006);
+		cart.setCustNo(1000006);
+		cart.setUpdNo(1000006);
 		cart.setJsessionId(TscSession.getSessionId());
 
 		// 장바구니 보유 CART_SQ 쿼리
@@ -188,9 +189,9 @@ public class TsfCartService {
 	public void saveNormalDealCartInfo(Cart param) {
 		// TODO 로그인 정보 세팅
 		param.setJsessionId(TscSession.getSessionId());
-		param.setRegNo(0);
-		param.setCustNo(0);
-		param.setUpdNo(0);
+		param.setRegNo(1000006);
+		param.setCustNo(1000006);
+		param.setUpdNo(1000006);
 
 		if("C".equals(param.getCartGb())) {
 			param.setCartGb(TscConstants.CartGb.CART.value());
@@ -236,9 +237,9 @@ public class TsfCartService {
 		// TODO 로그인 체크
 		order.setJsessionId(TscSession.getSessionId());
 		order.setJsessionId("aaec62cc-5f91-47bb-ba65-ebc9a61385cf");
-		order.setCustNo(0);
-		order.setRegNo(0);
-		order.setUpdNo(0);
+		order.setCustNo(1000006);
+		order.setRegNo(1000006);
+		order.setUpdNo(1000006);
 
 		// 장바구니 상품 조회
 		Collection<Order> cartGoodsList = cartDao.getCartGoodsList(order);

+ 186 - 0
src/main/java/com/style24/front/biz/service/TsfCouponService.java

@@ -1,9 +1,21 @@
 package com.style24.front.biz.service;
 
+import java.util.Collection;
+
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.thymeleaf.util.StringUtils;
 
+import com.style24.core.biz.dao.TscCouponDao;
+import com.style24.core.biz.service.TscCouponService;
+import com.style24.core.biz.service.TscOrderService;
+import com.style24.core.support.env.TscConstants;
 import com.style24.front.biz.dao.TsfCouponDao;
+import com.style24.front.support.security.session.TsfSession;
+import com.style24.persistence.domain.Coupon;
+import com.style24.persistence.domain.CustCoupon;
+import com.style24.persistence.domain.Order;
 
 import lombok.extern.slf4j.Slf4j;
 
@@ -20,4 +32,178 @@ public class TsfCouponService {
 	@Autowired
 	private TsfCouponDao couponDao;
 
+	@Autowired
+	private TscCouponDao coreCouponDao;
+
+	@Autowired
+	private TscOrderService coreOrderService;
+
+	/**
+	 * 시리얼 쿠폰 지급 정보 조회
+	 * @param param
+	 * @return
+	 * @author xodud1202
+	 * @since 2021. 02. 16
+	 */
+	public Coupon getSerialCpnUseInfo(Coupon param) {
+		return couponDao.getSerialCpnUseInfo(param);
+	}
+
+	/**
+	 * 시리얼 쿠폰 적용
+	 * @param param
+	 * @return
+	 * @author xodud1202
+	 * @since 2021. 02. 16
+	 */
+	public Coupon serialCpnApplyInfo(Coupon param) {
+		// TODO 로그인 정보 입력
+		param.setCustNo(1000006);
+		param.setRegNo(1000006);
+		param.setUpdNo(1000006);
+		param.setFrontGb(TsfSession.getFrontGb());
+
+		// 시리얼키의 쿠폰이 다운로드 가능한지 확인
+		Coupon cpn = couponDao.getSearchSerialCpnInfo(param);   // >> 여기서 쿠폰 정보 다 빼내야함.
+
+
+		// 다운로드 받을 수 있는 쿠폰이 있으면
+		if(cpn != null && cpn.getCpnId() > 0) {
+			// 다운 받을 수 있는 쿠폰ID를 내가 받은 이력이 있는지 확인
+			cpn.setCustNo(param.getCustNo());
+			Coupon myCpn = couponDao.getSerialCpnUseInfo(cpn);
+
+			// 다운로드 받은 쿠폰이 있는 경우
+			if(myCpn != null && myCpn.getCpnId() > 0) {
+				// 이미 다운 받았고, 사용 한 쿠폰이 있을 경우 종료
+				if(!StringUtils.isEmpty(myCpn.getUsedDt())) {
+					cpn.setResult("해당 쿠폰은 이미 사용하신 쿠폰입니다.");
+				} else {
+					cpn.setResult("지급 받으신 쿠폰 사용 기한이 지났습니다.");
+				}
+				return cpn;
+			} else {
+				/* 다운받지 않은 경우 (tb_cust_coupon insert) */
+				// 랜덤쿠폰 할당 및 쿠폰 지급
+				cpn.setRegNo(param.getRegNo());
+				cpn.setUpdNo(param.getUpdNo());
+				updateGiveRandomCpnInfo(cpn);
+			}
+		} else {
+			// 다운로드 받을 수 있는 쿠폰이 존재하지 않음.
+			cpn.setResult("해당 쿠폰은 존재하지 않습니다.");
+			return cpn;
+		}
+
+		// 장바구니쿠폰 토탈 할인 금액 계산
+		cpn.setDcAmt(getCartCpnApplyTotalAmt(param));
+		cpn.setResult("SUCCESS");
+
+		log.info("CHECK INFO >> {} / {}", cpn.getDcAmt(), cpn.getResult());
+
+		return cpn;
+
+
+
+/*
+		// 시리얼 쿠폰 지급 및 사용 내역 조회
+		Coupon useSerial = getSerialCpnUseInfo(param);
+		if(useSerial == null) {	useSerial = new Coupon();	}
+
+		useSerial.setRdCpnNm(param.getRdCpnNm());
+		useSerial.setCartSqArr(param.getCartSqArr());
+		useSerial.setCustNo(param.getCustNo());
+		useSerial.setRegNo(param.getRegNo());
+		useSerial.setUpdNo(param.getUpdNo());
+
+		Coupon coupon = new Coupon();
+
+		// 시리얼 쿠폰 다운로드하지 않았다면
+		if(useSerial != null && useSerial.getCpnId() > 0) {
+			// 해당 시리얼쿠폰을 사용한적이 있는 경우나, 받은것이 있는경우에 대한 처리
+			if(!StringUtils.isEmpty(useSerial.getUsedDt())) {
+				useSerial.setResult("해당 쿠폰은 이미 사용완료된 쿠폰입니다.");
+				return useSerial;
+			}
+		} else {
+			// 쿠폰 저장 및 할인 가격 적용
+			coupon = couponDao.getSearchSerialCpnInfo(useSerial);
+			if(coupon == null) {
+				useSerial.setResult("해당 쿠폰은 존재하지 않습니다.");
+				return useSerial;
+			} *//*else if (!"Y".equals(coupon.getDownCanGb())) {
+				useSerial.setResult("해당 쿠폰은 사용 할 수 없습니다.");
+				return useSerial;
+			}*//* else {
+				// 랜덤쿠폰 할당 및 쿠폰 지급
+				coupon.setCustNo(useSerial.getCustNo());
+				coupon.setRegNo(useSerial.getRegNo());
+				coupon.setUpdNo(useSerial.getUpdNo());
+				updateGiveRandomCpnInfo(coupon);
+			}
+		}*/
+	}
+
+	// 장바구니쿠폰 토탈 할인 금액 계산
+	public int getCartCpnApplyTotalAmt(Coupon param) {
+		// 쿠폰 할당 금액 세팅
+		Order order = new Order();
+		order.setCustNo(param.getCustNo());
+		order.setCartSqArr(param.getCartSqArr());
+		order.setCpnId(param.getCpnId());
+		order.setFrontGb(TsfSession.getFrontGb());
+
+		// 장바구니에 등록된 상품 중 적용 상품 조회
+		int totDcAmt = 0;
+		int totCurrPrice = 0;
+		int maxDcAmt = 0;
+		int buyLimitAmt = 0;
+
+		Collection<Order> serialGoodsList = coreOrderService.getSerialCpnApplyGoodsList(order);
+
+		// 각 필요 데이터 세팅
+		for(Order info : serialGoodsList) {
+			totCurrPrice = totCurrPrice + info.getCurrPrice();				// 적용 상품 구매 금액 합계((즉시할인쿠폰 + 옵션추가) * 수량)
+			maxDcAmt = info.getMaxDcAmt();									// 최대할인율과 최소주문금액은 한 쿠폰에 값이 동일
+			buyLimitAmt = info.getBuyLimitAmt();							// 최대할인율과 최소주문금액은 한 쿠폰에 값이 동일
+			if(TscConstants.DcWay.RATE.value().equals(info.getDcWay())) {	// 할인방식이 할인율이면 각 상품별 할인금액을 따로 계산해야함
+				int dcAmt = (int) (info.getCurrPrice() * (info.getDcVal() / 100.0));		// 해당상품 할인금
+				totDcAmt = totDcAmt + dcAmt;								// 적용 상품 총 할인금액
+			} else {														// 할인 방식이 금액일 경우
+				totDcAmt = info.getDcVal();
+			}
+		}
+
+		// 최대 할인 금액 요건 확인 (0은 제한 없음. 최대 할인 금액보다 할인금액이 크다면 최대할인금액만큼만 할인)
+		if(maxDcAmt > 0 && maxDcAmt < totDcAmt) {
+			totDcAmt = maxDcAmt;
+		}
+
+		// 주문 최소 금액 요건 확인 (0은 제한 없음. 최소 주문 금액보다 총 상품 금액이 적으면 0원으로 세팅)
+		if(buyLimitAmt > 0 && buyLimitAmt > totCurrPrice) {
+			totDcAmt = 0;
+		}
+
+		return totDcAmt;
+	}
+
+	@Transactional("shopTxnManager")
+	public void updateGiveRandomCpnInfo(Coupon param) {
+		// 랜덤쿠폰 할당 및 쿠폰 지급
+		CustCoupon custCoupon = new CustCoupon();
+		custCoupon.setCustNo(param.getCustNo());
+		custCoupon.setRegNo(param.getRegNo());
+		custCoupon.setUpdNo(param.getUpdNo());
+		custCoupon.setCpnId(param.getCpnId());
+		custCoupon.setRdCpnId(param.getRdCpnId());
+		custCoupon.setEndAlimSendYn("N");		// 알림 발송 여부(발송되면 Y)
+		custCoupon.setAvailStdt(param.getAvailStdt());
+		custCoupon.setAvailEddt(param.getAvailEddt());
+		custCoupon.setPubReason("G068_60");		// 쿠폰 발행사유 (랜덤쿠폰등록)
+		custCoupon.setPubReasonDtl(param.getRdCpnNm() + " 쿠폰 등록");
+
+		// 트랜잭션을 묶기 위해 dao 직접 호출
+		coreCouponDao.updateGiveRandomCoupon(custCoupon);		// 랜덤쿠폰 CUST_NO UPDATE
+		coreCouponDao.saveCouponCustPub(custCoupon);			// 랜덤쿠폰 고객 지급
+	}
 }

+ 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 - 고객번호

+ 188 - 0
src/main/java/com/style24/front/biz/service/TsfOrderService.java

@@ -2,12 +2,16 @@ package com.style24.front.biz.service;
 
 import java.text.DateFormat;
 import java.text.SimpleDateFormat;
+import java.util.ArrayList;
 import java.util.Calendar;
+import java.util.Collection;
 import java.util.Date;
+import java.util.List;
 
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
+import com.gagaframework.web.parameter.GagaMap;
 import com.style24.front.biz.dao.TsfOrderDao;
 import com.style24.persistence.domain.Order;
 
@@ -48,4 +52,188 @@ public class TsfOrderService {
 		return period; 
 	}
 
+	/**
+	 * 마이페이지 주문 정보 조회
+	 *
+	 * @param Order
+	 * @author card007
+	 * @since 2021. 02. 04
+	 */
+	public Collection<GagaMap> getOrderListForMypage(Order order) {
+		Collection<GagaMap> mapList = new ArrayList<>();
+		List<Order> orderList = new ArrayList<>();
+		int ordNo = 0;
+		String ordDt = "";
+		String delvFeeCd = "";
+		String ordDtlStat = "";
+		String shotDelvYn = "";
+		String selfGoodsYn = "";
+		String shipCompNm = "";
+		String invoiceNo = "";
+		String giftPackYn = "";
+		int reviewSq = 0;
+		int index = 0;
+		int ordDtlStatCnt = 0;
+		int rowspan = 0;
+
+		for (Order tmpOrder : orderDao.getOrderListForMypage(order)) {
+			// 주문번호, 배송구분(총알배송, 일반배송, 업체직배송), 배송정책 변경
+			if (ordNo != tmpOrder.getOrdNo() || !selfGoodsYn.equals(tmpOrder.getSelfGoodsYn()) || ("N".equals(tmpOrder.getSelfGoodsYn()) && !delvFeeCd.equals(tmpOrder.getDelvFeeCd())) || !shotDelvYn.equals(tmpOrder.getShotDelvYn())) {
+				// 데이터 설정
+				if (index > 0) {
+					GagaMap map = new GagaMap();
+					map.set("ordNo", ordNo);					// 주문번호
+					map.set("ordDt", ordDt);					// 주문일시
+					map.set("shotDelvYn", shotDelvYn);			// 총알배송여부
+					map.set("selfGoodsYn", selfGoodsYn);		// 자사여부
+					map.set("ordDtlStat", ordDtlStat);			// 주문상태코드
+					map.set("shipCompNm", shipCompNm);			// 배송업체명
+					map.set("invoiceNo", invoiceNo);			// 송장번호
+					map.set("giftPackYn", giftPackYn);			// 선물하기여부
+					map.set("reviewSq", reviewSq);				// 리뷰일련번호
+					map.set("orderList", setOrderListParameter(orderList, rowspan, ordDtlStatCnt, "Y"));			// 주문내역
+					mapList.add(map);
+				}
+
+				// 데이터 설정 후 초기화 진행
+				ordNo = tmpOrder.getOrdNo();
+				ordDt = tmpOrder.getOrdDt();
+				delvFeeCd = tmpOrder.getDelvFeeCd();
+				ordDtlStat = tmpOrder.getOrdDtlStat();
+				shotDelvYn = tmpOrder.getShotDelvYn();
+				selfGoodsYn = tmpOrder.getSelfGoodsYn();
+				shipCompNm = tmpOrder.getShipCompNm();
+				invoiceNo = tmpOrder.getInvoiceNo();
+				reviewSq = tmpOrder.getReviewSq();
+				giftPackYn = tmpOrder.getGiftPackYn();
+				orderList = new ArrayList<>();
+				ordDtlStatCnt = 0;
+				rowspan = 0;
+			} else if (index > 0 && !ordDtlStat.equals(tmpOrder.getOrdDtlStat())) {
+				// 주문내역 데이터 추가
+				orderList = setOrderListParameter(orderList, rowspan, ordDtlStatCnt, "N");
+
+				// 상태 별 배너 설정 후 초기화 진행
+				ordDtlStat = tmpOrder.getOrdDtlStat();
+				rowspan = 0;
+			}
+
+			// 주문내역 설정
+			orderList.add(tmpOrder);
+
+			// 인덱스 처리
+			index++;
+			ordDtlStatCnt++;
+			rowspan++;
+		}
+
+		// 마지막 데이터 설정
+		if (ordNo > 0) {
+			GagaMap map = new GagaMap();
+			map.set("ordNo", ordNo);
+			map.set("ordDt", ordDt);
+			map.set("shotDelvYn", shotDelvYn);
+			map.set("selfGoodsYn", selfGoodsYn);
+			map.set("ordDtlStat", ordDtlStat);
+			map.set("shipCompNm", shipCompNm);
+			map.set("invoiceNo", invoiceNo);
+			map.set("giftPackYn", giftPackYn);
+			map.set("reviewSq", reviewSq);
+			map.set("orderList", setOrderListParameter(orderList, rowspan, ordDtlStatCnt, "Y"));
+			mapList.add(map);
+		}
+
+		return mapList;
+	}
+
+	/**
+	 * 마이페이지 주문내역 데이터 추가
+	 *
+	 * @param List<Order>
+	 * @return List<Order>
+	 * @author card007
+	 * @since 2021. 02. 08
+	 */
+	private List<Order> setOrderListParameter(List<Order> orderList, int rowspan, int ordDtlStatCnt, String setLastBanner) {
+		// rowspan 설정
+		for (int i = 0;i <= rowspan;i++) {
+			if (i == rowspan) {
+				orderList.get(ordDtlStatCnt - rowspan).setRowspan(rowspan);
+			} else if (rowspan == 1){
+				orderList.get(ordDtlStatCnt - rowspan).setRowspan(1);
+			} else {
+				orderList.get(ordDtlStatCnt - rowspan).setRowspan(0);
+			}
+		}
+
+		// 주문상세상태값 별 배너 설정
+		if ("Y".equals(setLastBanner)) {
+			orderList.get(orderList.size() - 1).setOrdDtlStatBanner("Y");
+		} else {
+			orderList.get(ordDtlStatCnt - 1).setOrdDtlStatBanner("Y");
+		}
+
+		return orderList;
+	}
+
+	/**
+	 * 마이페이지 주문상태 별 주문수량 조회
+	 *
+	 * @param Order
+	 * @return int
+	 * @author card007
+	 * @since 2021. 02. 08
+	 */
+	public int getOrderStatCount(Order order) { return orderDao.getOrderStatCount(order); }
+
+	/**
+	 * 마이페이지 주문변경상태 별 주문수량 조회
+	 *
+	 * @param Order
+	 * @return int
+	 * @author card007
+	 * @since 2021. 02. 08
+	 */
+	public int getOrderChangeStatCount(Order order) { return orderDao.getOrderChangeStatCount(order); }
+
+	/**
+	 * 마이페이지 주문상세 금액정보 조회
+	 *
+	 * @param Order
+	 * @return Order
+	 * @author card007
+	 * @since 2021. 02. 16
+	 */
+	public Order getOrderAmtForMypage(Order order) { return orderDao.getOrderAmtForMypage(order); }
+
+	/**
+	 * 마이페이지 주문상세 결제정보 조회
+	 *
+	 * @param Order
+	 * @return Order
+	 * @author card007
+	 * @since 2021. 02. 16
+	 */
+	public Order getPaymentInfoForMypage(Order order) { return orderDao.getPaymentInfoForMypage(order); }
+
+	/**
+	 * 마이페이지 주문상세 배송지 정보 조회
+	 *
+	 * @param Order
+	 * @return Order
+	 * @author card007
+	 * @since 2021. 02. 16
+	 */
+	public Order getOrderDeliveryAddrInfo(Order order) { return orderDao.getOrderDeliveryAddrInfo(order); }
+
+	/**
+	 * 마이페이지 주문상세 주문내역삭제 처리
+	 *
+	 * @param Order
+	 * @return int
+	 * @author card007
+	 * @since 2021. 02. 17
+	 */
+	public int updateOrderDisplayYn(Order order) { return orderDao.updateOrderDisplayYn(order); }
+
 }

+ 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;
+	}
+
 
 }

+ 54 - 1
src/main/java/com/style24/front/biz/web/TsfCartController.java

@@ -1,6 +1,8 @@
 package com.style24.front.biz.web;
 
+import java.text.SimpleDateFormat;
 import java.util.Collection;
+import java.util.Date;
 
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.core.env.Environment;
@@ -12,12 +14,16 @@ import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.ResponseBody;
 import org.springframework.web.servlet.ModelAndView;
+import org.thymeleaf.util.StringUtils;
 
 import com.gagaframework.web.parameter.GagaMap;
+import com.style24.core.biz.service.TscOrderService;
 import com.style24.core.support.message.TscMessageByLocale;
 import com.style24.front.biz.service.TsfCartService;
+import com.style24.front.biz.service.TsfCouponService;
 import com.style24.front.support.controller.TsfBaseController;
 import com.style24.persistence.domain.Cart;
+import com.style24.persistence.domain.Coupon;
 import com.style24.persistence.domain.Order;
 
 import lombok.extern.slf4j.Slf4j;
@@ -39,6 +45,12 @@ public class TsfCartController extends TsfBaseController {
 	@Autowired
 	private TsfCartService cartService;
 
+	@Autowired
+	private TsfCouponService couponService;
+
+	@Autowired
+	private TscOrderService coreOrderService;
+
 	@Autowired
 	private Environment env;
 
@@ -88,9 +100,25 @@ public class TsfCartController extends TsfBaseController {
 
 	// @ResponseBody
 	@PostMapping("/goods/list")
-	public String selecCartGoodsList(Order param, Model model) {
+	public String selectCartGoodsList(Order param, Model model) {
+		// 장바구니 정보 조회
 		Order order = cartService.getCartGoodsList(param);
 
+		// 총알배송 가능 여부 체크
+		int shotCanYn = coreOrderService.getDailyDeliveryCheck(order);
+
+		// 10시 이전에만 총알 배송 가능 여부 체크
+		if(shotCanYn == 1) {
+			SimpleDateFormat format = new SimpleDateFormat ( "MM/dd");
+			Date time = new Date();
+
+			order.setShotCanYn("Y");
+			order.setShotDelvDt(format.format(time));
+		} else {
+			order.setShotCanYn("N");
+			order.setShotDelvYn("N");
+		}
+
 		model.addAttribute("param", param);
 		model.addAttribute("order", order);
 		model.addAttribute("wmsCartList", order.getWmsCartList());
@@ -99,4 +127,29 @@ public class TsfCartController extends TsfBaseController {
 
 		return super.getDeviceViewName("cart/cartListAjaxForm");
 	}
+
+	/**
+	 * 프로모션 할인 쿠폰 조회
+	 * @param param
+	 * rdCpnNm : 시리얼쿠폰명
+	 * cartSqArr[] : 장바구니 번호 배열
+	 * @return GagaMap
+	 * @author xodud1202
+	 * @since 2021. 02. 17
+	 */
+	@ResponseBody
+	@PostMapping("/list/serialCpnApply")
+	public GagaMap serialCpnApply(@RequestBody Coupon param) {
+		GagaMap result = new GagaMap();
+
+		log.info("CHECK IN >> {}", param.getRdCpnNm());
+		log.info("CHECK IN >> {}", param.getCartSqArr());
+
+		// 시리얼 쿠폰 정보 조회 및 쿠폰 지급 미대상인 경우 쿠폰 지급
+		Coupon useSerial = couponService.serialCpnApplyInfo(param);
+
+		result.put("serialCpnInfo", useSerial);
+
+		return result;
+	}
 }

+ 328 - 14
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,56 +42,280 @@ 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/IdFindForm"));
 
 		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("/password/find/form")
+	public ModelAndView pwdFindForm() {
 		ModelAndView mav = new ModelAndView();
 
-		mav.setViewName(super.getDeviceViewName("customer/FindIdResultForm"));
+		mav.setViewName(super.getDeviceViewName("customer/PasswordFindForm"));
 
 		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("/password/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("/password/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("authMethod", customer.getAuthMethod()); // 인증방법
+		result.setBoolean("isFind", isFind);
+		return result;
+	}
 
 	/**
-	 * 비밀번호 찾기 결과 화면
+	 * 비밀번호 변경 화면
 	 *
-	 * @param confirmYn - 인증여부
 	 * @return ModelAndView
 	 * @author jsshin
-	 * @since 2021. 02. 05
+	 * @since 2021. 02. 17
 	 */
-	@GetMapping("/pwd/find/result/form")
-	public ModelAndView pwdFindResult(@RequestParam(required = false) String confirmYn) {
+	@GetMapping("password/change/form")
+	public ModelAndView passwrodChangeForm(@RequestParam(value = "pageGb")String pageGb) {
 		ModelAndView mav = new ModelAndView();
+		String custNo = TscSession.getAttribute("custNo");
+
+		// 고객번호 없으면 인증화면으로 돌아감
+		if (StringUtils.isBlank(custNo)) {
+			String redirect = "redirect:/customer/password/find/form";
+			mav.setViewName(redirect);
+			return mav;
+		}
+
+		Customer params = new Customer();
+		params.setCustNo(Integer.valueOf(custNo));
 
-		mav.setViewName(super.getDeviceViewName("customer/FindPwdResultForm"));
+		// 고객정보 찾기
+		Customer custInfo = customerService.getCustomerFindId(params);
+		if (custInfo != null) {
+			mav.addObject("custId", custInfo.getCustId());
+		}
+
+		mav.setViewName(super.getDeviceViewName("customer/PasswordChangeForm"));
 		return mav;
 	}
 
+	/**
+	 * 비밀번호 변경
+	 *
+	 * @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;
+	}
+
+
 	/**
 	 * 회원정보 입력 화면
 	 *
@@ -95,9 +328,90 @@ public class TsfCustomerController extends TsfBaseController {
 		ModelAndView mav = new ModelAndView();
 
 		mav.setViewName(super.getDeviceViewName("customer/JoinForm"));
+
 		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;
+	}
 
 
 }

+ 140 - 17
src/main/java/com/style24/front/biz/web/TsfMypageController.java

@@ -5,9 +5,15 @@ 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.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
 import org.springframework.web.servlet.ModelAndView;
 
+import com.gagaframework.web.parameter.GagaMap;
+import com.gagaframework.web.rest.server.GagaResponseStatus;
 import com.style24.core.biz.service.TscCustomerService;
 import com.style24.core.biz.service.TscOrderService;
 import com.style24.core.support.env.TscConstants;
@@ -75,7 +81,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,15 +89,15 @@ public class TsfMypageController extends TsfBaseController {
 
 		// 고객정보 조회
 		Customer customer = new Customer();
+		customer.setSiteCd(TscConstants.Site.STYLE24.value());
 		customer.setCustNo(custNo);
-		customer = coreCustomerService.getCustomerInfo(customer);
-
-		mav.addObject("customerInfo", customer);
+		customer.setCustStat(TscConstants.CustStat.ACTIVE.value());
+		mav.addObject("customerInfo", coreCustomerService.getCustomerInfo(customer));
 
 		// 주문정보 조회
 		Order order = new Order();
 		order.setCustNo(custNo);
-		mav.addObject("orderInfo", coreOrderService.getOrderListForMypage(order));
+		mav.addObject("orderInfo", orderService.getOrderListForMypage(order));
 
 		// 쿠폰정보 조회
 		mav.addObject("couponCnt", coreOrderService.getCouponInfo(order));
@@ -104,40 +110,42 @@ public class TsfMypageController extends TsfBaseController {
 
 		// 상품권 정보 조회
 		mav.addObject("rmGfcdAmt", coreOrderService.getGiftcardInfo(order));
-		
-		// 바꿈
 
 		// 주문접수
 		order.setOrdDtlStat(TscConstants.OrderDetailStat.ORDER_RECEIPT.value());
-		mav.addObject("orderReceiptCount", coreOrderService.getOrderStatCount(order));
+		mav.addObject("orderReceiptCount", orderService.getOrderStatCount(order));
 
 		// 결제완료
 		order.setOrdDtlStat(TscConstants.OrderDetailStat.PAYMENT_COMPLETE.value());
-		mav.addObject("paymentCompleteCount", coreOrderService.getOrderStatCount(order));
+		mav.addObject("paymentCompleteCount", orderService.getOrderStatCount(order));
 
 		// 상품준비중
 		order.setOrdDtlStat(TscConstants.OrderDetailStat.GOODS_PREPARE.value());
-		mav.addObject("goodsPrepareCount", coreOrderService.getOrderStatCount(order));
+		mav.addObject("goodsPrepareCount", orderService.getOrderStatCount(order));
+
+		// 배송중
+		order.setOrdDtlStat(TscConstants.OrderDetailStat.DELIVERY_PREPARE.value());
+		mav.addObject("shipPrepareCount", orderService.getOrderStatCount(order));
 
 		// 배송중
 		order.setOrdDtlStat(TscConstants.OrderDetailStat.SHIPPING.value());
-		mav.addObject("shippingCount", coreOrderService.getOrderStatCount(order));
+		mav.addObject("shippingCount", orderService.getOrderStatCount(order));
 
 		// 배송완료
 		order.setOrdDtlStat(TscConstants.OrderDetailStat.DELIVERY_COMPLETE.value());
-		mav.addObject("shipCompleteCount", coreOrderService.getOrderStatCount(order));
+		mav.addObject("shipCompleteCount", orderService.getOrderStatCount(order));
 
 		// 취소내역
 		order.setChgStat(TscConstants.OrderChangeStat.CANCEL.value());
-		mav.addObject("cancelCount", coreOrderService.getOrderChangeStatCount(order));
+		mav.addObject("cancelCount", orderService.getOrderChangeStatCount(order));
 
 		// 반품내역
 		order.setChgStat(TscConstants.OrderChangeStat.RETURN.value());
-		mav.addObject("returnCount", coreOrderService.getOrderChangeStatCount(order));
+		mav.addObject("returnCount", orderService.getOrderChangeStatCount(order));
 
 		// 교환내역
 		order.setChgStat(TscConstants.OrderChangeStat.EXCHANGE.value());
-		mav.addObject("exchangeCount", coreOrderService.getOrderChangeStatCount(order));
+		mav.addObject("exchangeCount", orderService.getOrderChangeStatCount(order));
 		
 		// 검색기간 설정
 		mav.addObject("searchPeriod", orderService.getSearchPeriod());
@@ -146,7 +154,122 @@ 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);
+		
+		// 주문목록 조회
+		Collection<GagaMap> orderList = orderService.getOrderListForMypage(order);
+
+		if (orderList.size() == 0) {
+			throw new IllegalStateException(message.getMessage("ORDER_0001"));
+		}
+
+		mav.addObject("orderList", orderList);
+
+		// 주문정보 조회
+		mav.addObject("orderInfo", coreOrderService.getOrderInfoList(order).iterator().next());
+
+		// 주문 금액정보 조회
+		mav.addObject("orderAmtInfo", orderService.getOrderAmtForMypage(order));
+
+		// 주문 결제정보 조회
+		mav.addObject("paymentInfo", orderService.getPaymentInfoForMypage(order));
+		
+		// 주문 배송지 정보 조회
+		mav.addObject("deliveryAddrInfo", orderService.getOrderDeliveryAddrInfo(order));
+
+		mav.setViewName(super.getDeviceViewName("mypage/MypageOrderDetailForm"));
+
+		return mav;
+	}
+
+	/**
+	 * 마이페이지 주문상세 주문내역 삭제
+	 *
+	 * @return
+	 * @author card007
+	 * @since 2021. 02. 15
+	 */
+	@PostMapping("/order/delete")
+	@ResponseBody
+	public GagaMap deleteOrder(@RequestBody Order order) {
+		GagaMap result = new GagaMap();
+
+		// int custNo = TsfSession.getInfo().getCustNo();
+		int custNo = 1000007;
+		
+		order.setUpdNo(custNo);
+		
+		int chk = orderService.updateOrderDisplayYn(order);
+
+		if (chk > 0) {
+			result.set("message", message.getMessage("SUCC_0003"));
+			result.set("status", GagaResponseStatus.SUCCESS.getCode());
+		} else {
+			result.set("message", message.getMessage("FAIL_0003"));
+			result.set("status", GagaResponseStatus.FAIL.getCode());
+		}
+
+		return result;
+	}
+
+	/**
+	 * 마이페이지 구매확정 처리
+	 *
+	 * @return
+	 * @author card007
+	 * @since 2021. 02. 17
+	 */
+	@PostMapping("/order/decision")
+	@ResponseBody
+	public GagaMap decideOrder(@RequestBody Order order) {
+		GagaMap result = new GagaMap();
+
+		if (order.getOrdDtlNoArr().length == 0) {
+			result.set("message", message.getMessage("FAIL_1003"));
+			result.set("status", GagaResponseStatus.FAIL.getCode());
+			return result;
+		}
+
+		// int custNo = TsfSession.getInfo().getCustNo();
+		int custNo = 1000007;
+
+		order.setCustNo(custNo);
+		order.setRegNo(custNo);
+		order.setUpdNo(custNo);
+		
+		result = coreOrderService.decideOrder(order);
+		
+		return result;
+	}
 
 }

+ 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");
 	}
 
 }

+ 8 - 0
src/main/java/com/style24/persistence/domain/Cart.java

@@ -1,5 +1,6 @@
 package com.style24.persistence.domain;
 
+import com.fasterxml.jackson.annotation.JsonFormat;
 import com.fasterxml.jackson.annotation.JsonInclude;
 import com.style24.persistence.TscBaseDomain;
 import lombok.Data;
@@ -50,4 +51,11 @@ public class Cart extends TscBaseDomain {
 	// 다다익선 정보
 
 	// 즉시할인쿠폰 정보
+
+	// 시리얼쿠폰 정보
+	@JsonFormat(with = JsonFormat.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY)
+	private int[] cartSqArr;		// 장바구니 일련번호 배열 (일시품절제외 조회)
+	private String cpnNm;
+	private String rdCpnNm;
+	private String usedDt;
 }

+ 35 - 0
src/main/java/com/style24/persistence/domain/Coupon.java

@@ -0,0 +1,35 @@
+package com.style24.persistence.domain;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.style24.persistence.TscBaseDomain;
+
+import lombok.Data;
+
+/**
+ * 장바구니
+ *
+ * @author xodud1202
+ * @since 2021.01.22
+ */
+@SuppressWarnings("serial")
+@Data
+public class Coupon extends TscBaseDomain {
+	// 쿠폰 정보
+	@JsonFormat(with = JsonFormat.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY)
+	private int[] cartSqArr;		// 장바구니 일련번호 배열
+	private int cpnId;				// 쿠폰번호
+	private int custNo;				// 회원번호
+	private int availDays;			// 쿠폰 다운로드 후 유효기간일
+	private int rdCpnId;			// 랜덤쿠폰번호
+	private int dcAmt;				// 할인금액
+	private String useYn;			// 쿠폰 사용 여부
+	private String cpnNm;			// 쿠폰명
+	private String rdCpnNm;			// 시리얼쿠폰 키
+	private String usedDt;			// 쿠폰 사용완료 일자
+	private String result;			// 결과
+	private String pdGb;			// 기간/일수 구분 (P : 기간, D : 일수)
+	private String availStdt;		// 쿠폰 유효일
+	private String availEddt;		// 쿠폰 유효일
+	private String endAlimYn;		// 쿠폰 종료 알림 여부
+	private String frontGb;			// 화면 구분
+}

+ 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주소

+ 38 - 2
src/main/java/com/style24/persistence/mybatis/shop/TsfCoupon.xml

@@ -13,7 +13,43 @@
 		       ) ORIGINAL
 		WHERE  NUMB BETWEEN #{pageable.startRow} AND #{pageable.endRow}
 	</sql>
-	
-	
 
+	<!-- 시리얼 쿠폰 지급 정보 조회 -->
+	<select id="getSerialCpnUseInfo" parameterType="Coupon" resultType="Coupon">
+		/* TsfCoupon.getSerialCpnUseInfo */
+		SELECT CC.CPN_ID
+			 , DATE_FORMAT(CC.USED_DT, '%Y-%m-%d') AS USED_DT
+		FROM   TB_CUST_COUPON CC
+		WHERE  1=1
+		AND    CC.CPN_ID = #{cpnId}
+		AND    CC.CUST_NO = #{custNo}
+	</select>
+
+	<!-- 입력된 시리얼 쿠폰 정보 조회 -->
+	<select id="getSearchSerialCpnInfo" parameterType="Coupon" resultType="Coupon">
+		/* TsfCoupon.getSearchSerialCpnInfo : 입력된 시리얼 쿠폰 정보 조회 */
+		SELECT CP.CPN_ID
+			 , CP.CPN_NM
+		     , CP.DC_WAY
+			 , CASE WHEN #{frontGb} = 'P' THEN CP.DC_PVAL
+					WHEN #{frontGb} = 'M' THEN CP.DC_MVAL
+					ELSE CP.DC_AVAL END AS DC_VAL
+			 , RC.RD_CPN_NM
+		     , RC.RD_CPN_ID
+			 , CASE WHEN CP.PD_GB = 'D' THEN DATE_FORMAT(NOW(), '%Y%m%d%H%i%S')
+			     	ELSE DATE_FORMAT(CP.AVAIL_STDT, '%Y%m%d%H%i%S') END AS AVAIL_STDT
+			 , CASE WHEN CP.PD_GB = 'D' THEN DATE_FORMAT(DATE_ADD(NOW(), INTERVAL CP.AVAIL_DAYS DAY), '%Y%m%d%H%i%S')
+			     	ELSE  DATE_FORMAT(CP.AVAIL_EDDT, '%Y%m%d%H%i%S') END AS AVAIL_EDDT
+			 , CASE WHEN NOW() BETWEEN CP.DOWN_STDT AND CP.DOWN_EDDT THEN 'Y'
+					ELSE 'N' END AS downCanGb
+		FROM   TB_COUPON CP
+		INNER  JOIN TB_RANDOM_COUPON RC
+		ON     CP.CPN_ID = RC.CPN_ID
+		WHERE  1=1
+		AND    RC.RD_CPN_NM = #{rdCpnNm}
+		AND    NOW() BETWEEN CP.DOWN_STDT AND CP.DOWN_EDDT
+		ORDER  BY RC.CPN_ID
+		<!-- 랜덤쿠폰은 RD_CPN_NM이 1개이나, 시리얼 쿠폰은 다수개이므로 하나의 정보만 조회 -->
+		LIMIT  1
+	</select>
 </mapper>

+ 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">

+ 290 - 0
src/main/java/com/style24/persistence/mybatis/shop/TsfOrder.xml

@@ -15,4 +15,294 @@
 	</sql>
 	<!--// Paging -->
 
+	<!-- 마이페이지 주문 목록 조회 -->
+	<select id="getOrderListForMypage" parameterType="Order" resultType="Order">
+		/* TscOrder.getOrderListForMypage */
+		SELECT O.ORD_NO
+		     , DATE_FORMAT(O.ORD_DT, '%Y.%m.%d') AS ORD_DT
+		     , CASE OD.GIFT_PACK_YN WHEN 'Y' THEN DATE_FORMAT(O.ORD_DT + INTERVAL 3 DAY, '%Y.%m.%d')
+				END															AS GIFT_LIMIT_DT
+		     , CASE OD.GIFT_PACK_YN WHEN 'Y' THEN TIMESTAMPDIFF(DAY, NOW(), O.ORD_DT + INTERVAL 3 DAY)
+				END															AS GIFT_LIMIT_DAY
+		     , CASE OD.GIFT_PACK_YN WHEN 'Y' THEN DATE_FORMAT(DA.UPD_DT, '%Y.%m.%d')
+				END															AS GIFT_COMPLETE_DT
+		     , DATE_FORMAT(OD.DELV_EDDT, '%m/%d')							AS DELV_EDDT
+		     , OD.ORD_DTL_NO
+		     , OD.ORD_EXCH_GB
+		     , OD.GOODS_CD
+		     , G.GOODS_NM
+		     , ODI.OPT_CD
+		     , ODI.OPT_CD1
+		     , ODI.OPT_CD2
+		     , GI.SYS_IMG_NM
+		     , OD.ORD_DTL_STAT
+		     , OD.ORD_QTY
+		     , OD.ORD_AMT
+		     , OD.SAVE_PNT_AMT
+		     , OD.SHIP_COMP_CD
+		     , OD.GIFT_PACK_YN
+		     , (SELECT SHIP_COMP_NM
+				  FROM TB_SHIP_COMPANY Z
+				 WHERE Z.SHIP_COMP_CD = OD.SHIP_COMP_CD)					AS SHIP_COMP_NM
+		     , OD.INVOICE_NO
+		     , OD.SUPPLY_COMP_CD
+		     , OD.DELV_FEE_CD
+		     , OD.SHOT_DELV_YN
+		     , G.SELF_GOODS_YN
+		     , CONCAT(B.BRAND_ENM, ' ', B.BRAND_KNM)						AS BRAND_NM
+		     , FN_GET_CODE_NM('G013', OD.ORD_DTL_STAT)						AS ORD_DTL_STAT_NM
+		     , R.REVIEW_SQ
+		     , TIMESTAMPDIFF(DAY, NOW(), OD.DELV_EDDT + INTERVAL 2 WEEK)	AS PURCHASE_CONFIRM_DAY
+		     , DA.RECIP_NM
+		     , DA.RECIP_TELNO
+		     , DA.RECIP_PHNNO
+		     , DA.RECIP_ZIPCODE
+		     , DA.RECIP_BASE_ADDR
+		     , DA.RECIP_DTL_ADDR
+		  FROM TB_ORDER O
+		 INNER JOIN TB_ORDER_DETAIL OD
+		    ON O.ORD_NO = OD.ORD_NO
+		   AND OD.ORD_DTL_STAT NOT IN ('G013_11', 'G013_25', 'G013_97')
+		 INNER JOIN TB_ORDER_DETAIL_ITEM ODI
+		    ON OD.ORD_NO = ODI.ORD_NO
+		   AND OD.ORD_DTL_NO = ODI.ORD_DTL_NO
+		 INNER JOIN TB_GOODS G
+		    ON OD.GOODS_CD = G.GOODS_CD
+		 INNER JOIN TB_BRAND B
+		    ON B.BRAND_CD = G.BRAND_CD
+		  LEFT OUTER JOIN TB_REVIEW R
+		    ON R.ORD_NO = OD.ORD_NO
+		   AND R.ORD_DTL_NO = OD.ORD_DTL_NO
+		  LEFT OUTER JOIN TB_DELIVERY_ADDR DA
+		    ON DA.DELV_ADDR_SQ = OD.DELV_ADDR_SQ
+		  LEFT OUTER JOIN TB_GOODS_IMG GI
+		    ON OD.GOODS_CD = GI.GOODS_CD
+		   AND ODI.OPT_CD1 = GI.COLOR_CD
+		   AND GI.DEFAULT_IMG_YN = 'Y'
+		<where>
+			<choose>
+				<when test='custNo != null and custNo != ""'>
+		   AND O.CUST_NO = #{custNo}
+				</when>
+				<otherwise>
+		   AND O.ORD_NO = #{ordNo}
+		   AND O.ORD_NM = #{orderNm}
+				</otherwise>
+			</choose>
+			<if test="ordNo != null and ordNo != ''">
+		   AND O.ORD_NO = #{ordNo}
+			</if>
+			<choose>
+				<when test="stDate != null and stDate != '' and edDate != null and edDate != ''">
+		   AND O.ORD_DT BETWEEN DATE_FORMAT(CONCAT(#{stDate}, ' 000000'), '%Y-%m-%d %H%i%S') AND DATE_FORMAT(CONCAT(#{edDate}, ' 235959'), '%Y-%m-%d %H%i%S')
+				</when>
+				<otherwise>
+		   AND O.ORD_DT >= DATE_FORMAT(LAST_DAY(NOW() - INTERVAL 3 MONTH) + INTERVAL 1 DAY, '%Y-%m-%d')
+				</otherwise>
+			</choose>
+			<if test="ordDtlNoArr != null">
+		   AND OD.ORD_DTL_NO IN
+				<foreach collection="ordDtlNoArr" item="item" index="index"  open="(" close=")" separator=",">
+					#{item}
+				</foreach>
+			</if>
+		   AND O.DISP_YN = 'Y'
+		</where>
+		 ORDER BY OD.SUPPLY_COMP_CD
+				, OD.DELV_FEE_CD
+				, OD.ORD_NO DESC
+				, G.SELF_GOODS_YN DESC
+				, OD.SHOT_DELV_YN DESC
+				, OD.ORD_DTL_STAT
+	</select>
+
+	<!-- 마이페이지 주문상태 별 주문수량 조회 -->
+	<select id="getOrderStatCount" parameterType="Order" resultType="int">
+		/* TscOrder.getOrderStatCount */
+		SELECT COUNT(*) CNT
+		  FROM TB_ORDER O
+		 INNER JOIN TB_ORDER_DETAIL OD
+		    ON O.ORD_NO = OD.ORD_NO
+		<where>
+			<choose>
+				<when test='custNo != null and custNo != ""'>
+		   AND O.CUST_NO  =  #{custNo}
+				</when>
+				<otherwise>
+		   AND O.ORD_NO = #{ordNo}
+		   AND O.ORD_NM = #{orderNm}
+				</otherwise>
+			</choose>
+		</where>
+		<if test="ordDtlStat == 'G013_60'">
+		   AND O.ORD_DT >= DATE_FORMAT(CURRENT_DATE - INTERVAL 1 WEEK, '%Y-%m-%d')
+		</if>
+		   AND OD.ORD_DTL_STAT = #{ordDtlStat}
+		   AND O.DISP_YN = 'Y'
+	</select>
+
+	<!-- 마이페이지 주문변경상태 별 주문수량 조회 -->
+	<select id="getOrderChangeStatCount" parameterType="Order" resultType="int">
+		/* TscOrder.getOrderChangeStatCount */
+		SELECT COUNT(*) CNT
+		  FROM TB_ORDER_CHANGE_DETAIL OCD
+		 INNER JOIN TB_ORDER_DETAIL OD
+		    ON OCD.ORD_DTL_NO = OD.ORD_DTL_NO
+		 INNER JOIN TB_ORDER O
+		    ON O.ORD_NO = OD.ORD_NO
+		<where>
+			<choose>
+				<when test='custNo != null and custNo != ""'>
+		   AND O.CUST_NO  =  #{custNo}
+				</when>
+				<otherwise>
+		   AND O.ORD_NO = #{ordNo}
+		   AND O.ORD_NM = #{orderNm}
+				</otherwise>
+			</choose>
+		</where>
+		<choose>
+			<when test="chgStat == 'G685_30'">
+		   AND OCD.CHG_STAT IN (#{chgStat}, 'G685_33')
+			</when>
+			<otherwise>
+		   AND OCD.CHG_STAT = #{chgStat}
+			</otherwise>
+		</choose>
+		   AND O.DISP_YN = 'Y'
+	</select>
+
+	<!-- 마이페이지 주문목록 페이징 처리 주문번호 조회 -->
+	<select id="getPagingOrdNoList" parameterType="Order" resultType="Order">
+		/* TscOrder.getPagingOrdNoList */
+		<include refid="selectForPagingHeader"/>
+		SELECT ORD_NO
+		     , RANK() OVER(ORDER BY ORD_DT DESC) AS NUMB
+		  FROM TB_ORDER
+		 WHERE CUST_NO = #{custNo}
+		   AND DISP_YN = 'Y'
+		<include refid="selectForPagingFooter"/>
+	</select>
+
+	<!-- 마이페이지 주문상세 금액정보 조회 -->
+	<select id="getOrderAmtForMypage" parameterType="Order" resultType="Order">
+		/* TscOrder.getOrderAmtForMypage */
+		SELECT SUM(OD.ORD_AMT)          AS ORD_AMT
+			 , SUM(OD.CPN1_DC_AMT)      AS CPN1_DC_AMT
+			 , SUM(OD.TMTB1_DC_AMT)     AS TMTB1_DC_AMT
+			 , SUM(OD.TMTB2_DC_AMT)     AS TMTB2_DC_AMT
+			 , SUM(OD.CART_CPN_DC_AMT)  AS CART_CPN_DC_AMT
+			 , SUM(OD.GOODS_CPN_DC_AMT) AS GOODS_CPN_DC_AMT
+			 , SUM(OD.PRE_PNT_DC_AMT)   AS PRE_PNT_DC_AMT
+			 , SUM(OD.PNT_DC_AMT)       AS PNT_DC_AMT
+			 , SUM(OD.GFCD_USE_AMT)     AS GFCD_USE_AMT
+			 , SUM(OD.CPN1_DC_AMT + OD.TMTB1_DC_AMT + OD.TMTB2_DC_AMT + OD.CART_CPN_DC_AMT + OD.GOODS_CPN_DC_AMT + OD.PRE_PNT_DC_AMT + OD.PNT_DC_AMT + OD.GFCD_USE_AMT) AS TOTAL_DC_AMT
+			 , SUM(OD.REAL_ORD_AMT)     AS REAL_ORD_AMT
+			 , SUM(OD.SAVE_PNT_AMT)     AS SAVE_PNT_AMT
+			 , SUM(DF.DELV_FEE)         AS DELV_FEE
+		  FROM TB_ORDER_DETAIL OD
+		  LEFT OUTER JOIN (
+			  SELECT ORD_NO
+				   , SUM(DELV_FEE) AS DELV_FEE
+				FROM TB_DELIVERY_FEE
+			   WHERE ORD_NO = #{ordNo}
+				 AND DELV_FEE_GB = 'G018_10'
+			   GROUP BY ORD_NO
+		  ) DF
+		  ON OD.ORD_NO = DF.ORD_NO
+		 WHERE OD.ORD_NO = #{ordNo}
+	</select>
+
+	<!-- 마이페이지 주문상세 결제정보 조회 -->
+	<select id="getPaymentInfoForMypage" parameterType="Order" resultType="Order">
+		/* TscOrder.getPaymentInfoForMypage */
+		SELECT PAY_SQ
+		     , ORD_NO
+		     , PAY_DT
+		     , PAY_MEANS
+		     , PAY_AMT
+		     , PG_CPN_AMT
+		     , NPAY_PNT_AMT
+		     , PAY_GB
+		     , PAY_STAT
+		     , PG_GB
+		     , PG_TID
+		     , PG_TRADE_NO
+		     , PG_SHOP_ID
+		     , CARD_TYPE
+		     , CARD_KIND
+		     , CARD_BANK
+		     , CARD_NM
+		     , CARD_MIPS
+		     , CARD_PCABLE_YN
+		     , VA_NO
+		     , VA_NM
+		     , VA_BANK
+		     , VA_DEADLINE
+		     , DATE_FORMAT(VA_DEADLINE, '%Y.%m.%d') AS VA_DEADLINE_YMD
+		     , DATE_FORMAT(VA_DEADLINE, '%H:%i:%S') AS VA_DEADLINE_HMS
+		     , TELECOM
+		     , ESCROW_YN
+		     , ORD_CHG_SQ
+		     , REG_NO
+		     , REG_DT
+		     , UPD_NO
+		     , UPD_DT
+		  FROM TB_PAYMENT
+		<where>
+			<if test="ordNo != null and ordNo != ''">
+		   AND ORD_NO = #{ordNo}
+			</if>
+			<if test="paySq != null and paySq != ''">
+		   AND PAY_SQ = #{paySq}
+			</if>
+			<if test="ordChgSq != null and ordChgSq != ''">
+		   AND ORD_CHG_SQ = #{ordChgSq}
+			</if>
+			<if test="pgTid != null and pgTid != ''">
+		   AND PG_TID = #{pgTid}
+			</if>
+			<if test="payGb != null and payGb != ''">
+		   AND PAY_GB = #{payGb}
+			</if>
+			<if test="payStat != null and payStat != ''">
+		   AND PAY_STAT = #{payStat}
+			</if>
+			<if test="pgGb != null and pgGb != ''">
+		   AND PG_GB = #{pgGb}
+			</if>
+		</where>
+	</select>
+
+	<!-- 마이페이지 주문상세 배송지 정보 조회 -->
+	<select id="getOrderDeliveryAddrInfo" parameterType="Order" resultType="Order">
+		/* TscOrder.getOrderDeliveryAddrInfo */
+		SELECT DA.DELV_ADDR_SQ
+			 , DA.RECIP_NM
+			 , DA.RECIP_PHNNO
+			 , DA.RECIP_TELNO
+			 , DA.RECIP_ZIPCODE
+			 , DA.RECIP_BASE_ADDR
+			 , DA.RECIP_DTL_ADDR
+			 , DA.DELV_MEMO
+			 , DA.REG_NO
+			 , DA.REG_DT
+			 , DA.UPD_NO
+			 , DA.UPD_DT
+		  FROM TB_DELIVERY_ADDR DA
+		  INNER JOIN TB_ORDER_DETAIL OD
+		  ON OD.DELV_ADDR_SQ = DA.DELV_ADDR_SQ
+			  AND OD.ORD_NO = #{ordNo}
+		 LIMIT 1
+	</select>
+
+	<!-- 마이페이지 주문상세 주문내역삭제 처리 -->
+	<update id="updateOrderDisplayYn" parameterType="Order">
+		/* TsfOrder.updateOrderDisplayYn */
+		UPDATE TB_ORDER
+		   SET DISP_YN = 'N'
+		     , UPD_NO = #{updNo}
+		     , UPD_DT = NOW()
+		 WHERE ORD_NO = #{ordNo}
+	</update>
 </mapper>

+ 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:

+ 1 - 0
src/main/resources/i18n/messages/message_ko_KR.properties

@@ -22,6 +22,7 @@ FAIL_0007=\uC624\uB958\uB85C \uC778\uD574 \uC5C5\uB85C\uB4DC \uB418\uC9C0 \uC54A
 FAIL_0009=\uC624\uB958\uB85C \uC778\uD574 \uBCC0\uACBD\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4.
 FAIL_1001=\uC800\uC7A5\uD560 \uB370\uC774\uD130\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.
 FAIL_1002=\uC804\uC1A1\uD560 \uB370\uC774\uD130\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.
+FAIL_1003=\uCC98\uB9AC\uD560 \uB370\uC774\uD130\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.
 
 LOGN_0001=\uC785\uB825\uD558\uC2E0 \uC815\uBCF4\uB85C \uAC00\uC785\uB41C \uB0B4\uC5ED\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.
 LOGN_0002=\uBE44\uBC00\uBC88\uD638\uAC00 \uC77C\uCE58\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.

BIN=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';

+ 68 - 16
src/main/webapp/WEB-INF/views/web/cart/cartListAjaxFormWeb.html

@@ -1,8 +1,11 @@
 <html lang="ko"
       xmlns:th="http://www.thymeleaf.org">
+<form id="cartListForm" method="post" action="/order/noMember">
+    <input type="hidden" name="cartCpnDcAmt" id="cartCpnDcAmt" th:value="${param.cartCpnDcAmt}" />
+
 <!-- CONT-BODY -->
 <div class="od_cont">
-    <div class="sec_head">
+    <div class="sec_head" th:if="${order.shotCanYn.equals('Y')}">
         <div class="tbl type4">
             <table>
                 <colgroup>
@@ -17,12 +20,12 @@
                     <td>
                         <div class="form_field">
                             <div>
-                                <input type="radio" name="radio" id="blt_ship1" value="">
-                                <label for="blt_ship1"><span><em class="tag">총알배송</em>10/15일 24:00 까지 도착</span></label>
+                                <input type="radio" name="shotDelvYn" id="blt_ship1" value="">
+                                <label for="blt_ship1"><span><em class="tag">총알배송</em><span th:text="|${order.shotDelvDt}일 24:00 까지 도착|"></span></span></label>
                             </div>
                             <div>
-                                <input type="radio" name="radio" id="blt_ship2" value="" checked="">
-                                <label for="blt_ship2"><span>총알 배송 안함 (10/25일 도착 예정)</span></label>
+                                <input type="radio" name="shotDelvYn" id="blt_ship2" value="" checked="">
+                                <label for="blt_ship2"><span>총알 배송 안함</span></label>
                             </div>
                         </div>
                     </td>
@@ -34,13 +37,13 @@
     <div class="sec_body">
         <!-- 총알배송 -->
         <div class="part_deliver" th:if="${wmsCartList.size() > 0}">
-            <h3 class="subH2 mb20">
+            <h3 class="subH2 mb20" th:if="${order.shotCanYn.equals('Y')}">
                 STYLE24 총알배송
                 <span class="ml10">오늘 자정까지 도착</span>
             </h3>
-            <!--<h3 class="subH2 mb20">
+            <h3 class="subH2 mb20" th:if="${order.shotCanYn.equals('N')}">
                 STYLE24 일반배송
-            </h3>-->
+            </h3>
             <div class="tbl type2">
                 <table>
                     <colgroup>
@@ -55,8 +58,8 @@
                             <div class="info_item" th:classappend="${cart.soldoutYn.equals('Y')} ? unable"> <!-- 주문불가시 class="unable" 추가 / 인풋, 버튼 disable 처리 -->
                                 <div class="form_box">
                                     <p class="form_field">
-                                        <input id="od_item1" type="checkbox" th:value="${cart.cartSq}" th:checked="${cart.soldoutYn.equals('N')}" />
-                                        <label for="od_item1">
+                                        <input th:id="|od_item_${cart.cartSq}|" name="cartSqArr" type="checkbox" th:value="${cart.cartSq}" th:checked="${cart.soldoutYn.equals('N')}" th:disabled="${cart.soldoutYn.equals('Y')}"/>
+                                        <label th:for="|od_item_${cart.cartSq}|">
                                             <span class="sr-only">상품선택</span>
                                         </label>
                                     </p>
@@ -79,7 +82,7 @@
                                         <span class="count">수량:<em th:text="${cart.itemQtyArr[index.index]} * ${cart.goodsQty}"></em>개</span>
                                     </p>
                                     <p class="od_modify">
-                                        <button type="button" id="btn_opt_pop"><span>옵션/수량변경</span></button>
+                                        <button type="button"><span>옵션/수량변경</span></button>
                                     </p>
                                     <!-- 다다익선 적용 -->
                                     <div class="od_moresale" th:if="${cart.applyQtySectionYn == 'Y' or cart.applyAmtSectionYn == 'Y'}">
@@ -173,7 +176,7 @@
                             <div class="info_item">
                                 <div class="form_box">
                                     <p class="form_field">
-                                        <input id="od_item_21" type="checkbox" th:value="${cart.cartSq}" th:checked="${cart.soldoutYn.equals('N')}">
+                                        <input id="od_item_21" name="cartSqArr" type="checkbox" th:value="${cart.cartSq}" th:checked="${cart.soldoutYn.equals('N')}">
                                         <label for="od_item_21">
                                             <span class="sr-only">상품선택</span>
                                         </label>
@@ -293,14 +296,14 @@
                 </div>
                 <div>
                     <dt>할인금액</dt>
-                    <dd><span class="disc_amount"><em th:text="${#numbers.formatInteger(order.totDcAmt, 1, 'COMMA')}"></em>원</span></dd>
+                    <dd><span class="disc_amount"><em id="totDcAmt" th:text="${#numbers.formatInteger(order.totDcAmt, 1, 'COMMA')}"></em>원</span></dd>
                 </div>
             </dl>
         </div>
         <div class="totalprice_box">
             <dl>
                 <dt>총 결제 예정 금액</dt>
-                <dd data-weight="price" data-font="lato"><span th:text="${#numbers.formatInteger(order.sumRealPayAmt, 1, 'COMMA')}"></span>원</dd>
+                <dd data-weight="price" data-font="lato"><span id="sumRealPayAmt" th:text="${#numbers.formatInteger(order.sumRealPayAmt, 1, 'COMMA')}"></span>원</dd>
             </dl>
         </div>
         <div class="btn_box">
@@ -312,9 +315,9 @@
         <div class="form_field">
             <div class="input_wrap form_full">
                 <label class="input_label sr-only">할인코드입력</label>
-                <input type="text" class="form_control" placeholder="할인코드를 입력해주세요.">
+                <input type="text" id="serialCpnNm" class="form_control" placeholder="할인코드를 입력해주세요.">
             </div>
-            <button type="button" class="btn btn_dark btn_default"><span>적용</span></button>
+            <button type="button" class="btn btn_dark btn_default" onclick="serialCpnApply()"><span>적용</span></button>
         </div>
         <div class="coupon_box">
             <div class="coupon">
@@ -405,4 +408,53 @@
 </div>
 <div class="clear"></div>
 <!-- // CONT-BODY -->
+</form>
+
+<script type="text/javascript">
+    let sumRealPayAmt = [[${order.sumRealPayAmt}]];
+    let totDcAmt = [[${order.totDcAmt}]];
+
+    $(document).ready(function() {
+        $("#sumRealPayAmt").text(Number(sumRealPayAmt).toLocaleString());
+        $("#totDcAmt").text(Number(totDcAmt).toLocaleString());
+        //$("#cartListForm").submit();
+       /* $.ajax( {
+            type: "POST",
+            url : '/cart/goods/list',
+            dataType : 'html',
+            success : function(result) {
+                if (result != null) {
+                    $("#cartAjaxList").html(result);
+                }
+            }
+        });*/
+    });
+
+    function serialCpnApply() {
+        let testArr = [];
+        $("#cartListForm input[name=cartSqArr]").each(function(index, item) {
+            testArr.push($(this).val());
+        });
+
+        let data = {
+            rdCpnNm : $("#serialCpnNm").val(),
+            cartSqArr : testArr
+        }
+
+        let jsonData = JSON.stringify(data);
+
+        $.ajax( {
+            type: "POST",
+            url : '/cart/list/serialCpnApply',
+            contentType: 'application/json',
+            dataType : 'json',
+            data : jsonData,
+            success : function(result) {
+                alert(result.serialCpnInfo.result + " / " + result.serialCpnInfo.dcAmt);
+                $("#sumRealPayAmt").text(Number(sumRealPayAmt - result.serialCpnInfo.dcAmt).toLocaleString());
+                $("#totDcAmt").text(Number(totDcAmt - result.serialCpnInfo.dcAmt).toLocaleString());
+            }
+        });
+    };
+</script>
 </html>

+ 1 - 0
src/main/webapp/WEB-INF/views/web/cart/cartListFormWeb.html

@@ -418,6 +418,7 @@
     });
 
     function getCartList() {
+        // 장바구니 정보 조회
         $.ajax( {
             type: "POST",
             url : '/cart/goods/list',

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

@@ -26,12 +26,14 @@
 	<link rel="icon" href="/images/favicon-16x16.png" sizes="16x16" type="image/png"/>
 	
 	<link rel="stylesheet" type="text/css" th:href="@{'/ux/pc/css/common.css?v=' + ${#calendars.format(#calendars.createNow(), 'yyyyMMddHHmmss')}}" href="/ux/pc/css/common.css"/>
+	<link rel="stylesheet" type="text/css" href="/ux/pc/css/jquery-ui.css">
 	<link rel="stylesheet" type="text/css" href="/ux/pc/css/slick.css" />
 	
 	<script src="http://code.jquery.com/jquery-1.9.1.js"></script>
 	<script src="/ux/pc/js/slick.min.js"></script>
 	<script src="/ux/pc/js/jquery-ui.js"></script>
 	<script src="/ux/pc/js/jquery.modal.min.js"></script>
+	<script src="/ux/pc/js/jquery.ui.datepicker.monthyearpicker.js"></script>
 	<script src="/ux/plugins/jquery.serializeObject.min.js"></script>
 	<script src="/ux/plugins/mcxdialog/mcxdialog_ui.js"></script>
 

+ 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>

+ 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>

+ 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>

+ 333 - 0
src/main/webapp/WEB-INF/views/web/customer/IdFindFormWeb.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  : IdFindFormWeb.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>

+ 70 - 28
src/main/webapp/WEB-INF/views/web/customer/JoinFormWeb.html

@@ -17,8 +17,11 @@
  *******************************************************************************
  -->
 <body>
-
 <th:block layout:fragment="content">
+<style>
+	.show{display:block}
+	.hide{display:none}
+</style>
 <div id="container" class="container mb">
 	<div class="wrap">
 		<div class="content join2"> <!-- 페이지특정 클래스 = join1 -->
@@ -27,7 +30,7 @@
 			</div>
 			<div class="cont_body">
 				<!-- form start -->
-				<form class="form_wrap form_col_c form_full" role="form">
+				<form id="joinForm" name="joinForm" class="form_wrap form_col_c form_full" role="form">
 					<div class="form_head">
 						<h4>회원정보 입력</h4>
 					</div>
@@ -35,41 +38,39 @@
 					<div class="form_field">
 						<label class="input_label sr-only">아이디</label>
 						<div class="input_wrap form_full">
-							<input type="text" name="userId" placeholder="아이디" value="moon123" class="form_control usable" id="txtId"><!-- class "usable" 추가 -->
+							<input type="text" id="custId" name="custId" placeholder="아이디 (4~12자)" class="form_control" required="required" data-valid-type="alphaNumeric" data-valid-name="아이디" minlength="4" maxlength="12"/>
 							<span class="usable" style="display:block;"></span><!-- display:block / display:none 으로 control -->
 						</div>
-					</div>
-					<!-- //아이디 사용가능시 -->
-					<!-- 아이디 사용불가시 -->
-					<div class="form_field">
-						<label class="input_label sr-only">아이디</label>
-						<div class="input_wrap form_full">
-							<input type="text" name="userId" placeholder="아이디" value="abcd1234" class="form_control err" id="txtId"><!-- 잘못기입된 경우 class "err" 추가 -->
-							<span class="usable"></span>
-						</div>
-						<div class="help_block">
+						<div id="dupCustIdDiv" class="help_block hide">
 							<p class="t_err">이미 가입된 아이디입니다.다른 아이디를 입력하여 주세요.</p>
 						</div>
 					</div>
-					<!-- //아이디 사용불가시 -->
-
+					<!-- //아이디 사용가능시 -->
 					<!-- 오류시 부모 div에서 제어 -->
 					<div class="form_field">
 						<label class="input_label sr-only">비밀번호</label>
 						<div class="input_wrap form_full">
-							<input type="password" name="userPassword" placeholder="비밀번호 (8~20자 영문, 숫자, 특수문자 중 2가지 이상 조합)" class="form_control" id="txtPassword"><!-- 잘못기입된 경우 class "err" 추가 -->
+							<input type="password" id="passwd" name="passwd" placeholder="비밀번호 (8~20자 영문, 숫자, 특수문자 중 2가지 이상 조합)" class="form_control" minlength="8" maxlength="20" required="required" data-valid-name="비밀번호"/><!-- 잘못기입된 경우 class "err" 추가 -->
 							<!-- 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>
+									<span class="c_black2">
+										<i class="ico ico_check black mr5"></i>영문(대/소문자), 숫자, 특수문자 중 2가지 이상 조합(8~20자)<br>
+									</span>
+									<span class="c_red2">
+										<i class="ico ico_check red mr5"></i>4개이상 연속되거나 동일한 문자/숫자 제외<br>
+									</span>
+									<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>
+									<span class="c_black2">
+										<i class="ico ico_check black mr5"></i>사용 가능한 비밀번호입니다
+									</span>
 								</p>
 								<!-- //사용가능한 비밀번호일경우 -->
 							</div>
@@ -80,7 +81,7 @@
 					<div class="form_field">
 						<label class="input_label sr-only">비밀번호 확인</label>
 						<div class="input_wrap form_full">
-							<input type="password" name="userConfirm" placeholder="비밀번호 확인" class="form_control" id="txtConfirm"><!-- 잘못기입된 경우 class "err" 추가 -->
+							<input type="password" id="confirmPassword" name="confirmPassword" placeholder="비밀번호 확인" class="form_control" minlength="8" maxlength="20" required="required" data-valid-name="비밀번호"/><!-- 잘못기입된 경우 class "err" 추가 -->
 							<!-- case (비밀번호확인 틀렸을경우,비밀번호 일치할경우) -->
 							<div class="help_block">
 								<!-- 비밀번호확인 틀렸을경우 -->
@@ -100,7 +101,7 @@
 					<div class="form_field">
 						<label class="input_label sr-only">이메일</label>
 						<div class="input_wrap form_full">
-							<input type="text" name="userEmail" placeholder="이메일" class="form_control" id="txtEmail"><!-- 잘못기입된 경우 class "err" 추가 -->
+							<input type="text" id="email" name="email" placeholder="이메일" class="form_control" maxlength="30"/><!-- 잘못기입된 경우 class "err" 추가 -->
 							<!-- case (이메일 형식이 바르지않을경우,이미 가입되어있는 이메일인경우) -->
 							<div class="help_block">
 								<!-- 이메일 형식이 바르지않을경우 -->
@@ -113,8 +114,12 @@
 									이미 가입된 이메일 주소입니다. 다른 이메일 주소를 입력하여 주세요.
 								</p>
 								<div class="mt20">
-									<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" onclick="cfnGoToPage(_PAGE_LOGIN);">
+										<span>로그인</span>
+									</button>
+									<button type="button" class="btn btn_default btn_sm" onclick="cfnGoToPage(_PAGE_CUSTOMER_ID_FIND);">
+										<span>아이디 찾기</span>
+									</button>
 								</div>
 								<!-- //이미 가입되어있는 이메일인경우 -->
 							</div>
@@ -124,7 +129,7 @@
 					<div class="form_field">
 						<label class="input_label sr-only">휴대폰번호</label>
 						<div class="input_wrap form_full">
-							<input type="text" name="userTell" placeholder="휴대폰번호" class="form_control" id="txtTell">
+							<input type="text" id="cellPhnno" name="cellPhnno" placeholder="휴대폰번호" class="form_control"/>
 							<!-- case (휴대폰번호 형식이 맞지 않을경우,이미 가입되어있는 핸드폰번호일경우) -->
 							<div class="help_block">
 								<!-- 휴대폰번호 형식이 맞지 않을경우 -->
@@ -133,7 +138,9 @@
 								<!-- 이미 가입되어있는 핸드폰번호일경우 -->
 								<p class="t_err">I***D로 가입된 핸드폰 번호 입니다.</p>
 								<div class="mt20">
-									<button type="button" class="btn btn_default btn_sm"><span>휴대폰 인증</span></button>
+									<button type="button" class="btn btn_default btn_sm">
+										<span>휴대폰 인증</span>
+									</button>
 								</div>
 								<!-- //이미 가입되어있는 핸드폰번호일경우 -->
 							</div>
@@ -145,8 +152,8 @@
 					</div>
 					<div class="desc_wrap t_c mt20">
 						<p>
-							본인은&nbsp;만 14세 이상이며&nbsp;<a href="" target="_blank">STYLE24이용약관<i class="ico ico_blank ml5"></i></a>,&nbsp;<a href="" target="_blank">개인정보 수집 및 이용<i class="ico ico_blank ml5"></i></a>,<br>
-							<a href="" target="_blank">개인정보 취급 위탁<i class="ico ico_blank ml5"></i></a> 내용을 확인 하였으며,동의합니다.
+							본인은&nbsp;만 14세 이상이며&nbsp;<a href="javascript:void(0)" target="_blank">STYLE24이용약관<i class="ico ico_blank ml5"></i></a>,&nbsp;<a href="javascript:void(0)" target="_blank">개인정보 수집 및 이용<i class="ico ico_blank ml5"></i></a>,<br>
+							<a href="javascript:void(0)" target="_blank">개인정보 취급 위탁<i class="ico ico_blank ml5"></i></a> 내용을 확인 하였으며,동의합니다.
 						</p>
 					</div>
 				</form>
@@ -156,8 +163,43 @@
 	</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[*/
+	//	중복된 아이디 확인
+	$('#custId').on('blur', function () {
+		let custId = $(this).val();
+		if(!gagajf.isNull(custId)) {
+			let custInfo = {};
+			custInfo.custId = custId;
+			let jsonData = JSON.stringify(custInfo);
+			ajaxJsonSubmit('/customer/id/check', jsonData, fnIdConfirmCallBack)
+		}
+
+	});
+
+	var fnIdConfirmCallBack = function (result) {
+		if (result.isFind) { // 중복된 아이디가 존재
+			fnDisplayCustIdDiv(false);
+		} else {
+			fnDisplayCustIdDiv(true);
+		}
+	};
+
+	var fnDisplayCustIdDiv = function (bool) {
+		let $dupCustIdDiv = $('#dupCustIdDiv');
+		let $custId = $('#custId');
+		if (bool) { // 사용가능
+			$custId.removeClass('err'); //잘못기입된 경우
+			$custId.addClass('usable');
+			$('.usable').show();
+		} else {  // 사용가능 하지 않음
+			$custId.addClass('err'); //잘못기입된 경우
+			$custId.removeClass('usable');
+			$dupCustIdDiv.show();
+			$('.usable').hide();
+		}
+	};
 
 /*]]>*/
 </script>

+ 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>

+ 247 - 0
src/main/webapp/WEB-INF/views/web/customer/PasswordChangeFormWeb.html

@@ -0,0 +1,247 @@
+<!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  : PasswordChangeFormWeb.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 show">
+				<form id="resetPasswordForm" name="resetPasswordForm" class="form_wrap form_col_c" role="form" method="post">
+					<div class="form_head">
+						<h4>아이디&#47;비밀번호 찾기</h4>
+					</div>
+					<!-- 비밀번호 재설정 -->
+					<div class="find_result clear" >
+						<input type="hidden" name="custId" th:value="${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">
+									<!-- 사용불가 비밀번호일경우 c_gray c_black2 c_red2-->
+									<p class="mt10">
+										<span id="firstFailed" class="c_gray">
+											<i class="ico ico_check gray mr5"></i>영문(대/소문자), 숫자, 특수문자 중 2가지 이상 조합(8~20자) <br/>
+										</span>
+										<span id="secondFailed" class="c_gray">
+											<i class="ico ico_check gray mr5"></i>4개이상 연속되거나 동일한 문자/숫자 제외 <br/>
+										</span>
+										<span id="thirdFailed" class="c_gray">
+											<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>
+					</div>
+					<!-- //비밀번호 재설정 -->
+				</form>
+			</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[*/
+
+	// 비밀번호 입력
+	$('#resetPasswordForm input[name=passwd]').on('focusout keyup keydown', function () {
+		fnCheckPassword();
+	});
+
+	// 비밀번호 확인 입력
+	$('#resetPasswordForm input[name=confirmPassword]').on('focusout keyup keydown', function () {
+		fnCheckConfirmPassword();
+	});
+
+	// 비밀번호 확인
+	var fnCheckPassword = function () {
+		let custId = $('#resetPasswordForm input[name=custId]').val();
+		let password = $('#resetPasswordForm input[name=passwd]').val();
+		let confirmPassword = $('#resetPasswordForm input[name=confirmPassword]').val();
+		let $firstFailed = $('#firstFailed');
+		let $secondFailed = $('#secondFailed');
+		let $thirdFailed = $('#thirdFailed');
+		let $avlPwd = $('#avlPwd');
+		let pwdCheck = true;
+		let red = 'c_red2';
+		let gray = 'c_gray';
+
+		// 영문, 숫자, 특수문자 2종 이상 혼용 || 길이
+		if (fnValidtaionPwdMixedWord(password) || fnValidationPwdLength(password)) {
+			pwdCheck = false;
+			$firstFailed.removeClass(gray);
+			$firstFailed.addClass(red);
+		} else {
+			$firstFailed.removeClass(red);
+			$firstFailed.addClass(gray);
+		}
+
+		// 동일한 문자/숫자 4자이상 || 연속된 문자가 4자이상
+		if (fnValidationPwdSameWord(password) || fnValidtaionPwdCntnsWord(password)) {
+			pwdCheck = false;
+			$secondFailed.removeClass(gray);
+			$secondFailed.addClass(red);
+		} else {
+			$secondFailed.removeClass(red);
+			$secondFailed.addClass(gray);
+		}
+
+		// 아이디 포함
+		if (fnValidationPwdSameId(password, custId)) {
+			pwdCheck = false;
+			$thirdFailed.removeClass(gray);
+			$thirdFailed.addClass(red);
+		} else {
+			$thirdFailed.removeClass(red);
+			$thirdFailed.addClass(gray);
+		}
+
+		if (pwdCheck) {
+			$firstFailed.hide();
+			$secondFailed.hide();
+			$thirdFailed.hide();
+			$avlPwd.show();
+		} else {
+			$firstFailed.show();
+			$secondFailed.show();
+			$thirdFailed.show();
+			$avlPwd.hide();
+		}
+
+		if (!gagajf.isNull(confirmPassword)) {
+			fnCheckConfirmPassword();
+		}
+
+	};
+
+	// 비밀번호체크
+	var fnCheckConfirmPassword = function () {
+		let password = $('#resetPasswordForm input[name=passwd]').val();
+		let confirmPassword = $('#resetPasswordForm input[name=confirmPassword]').val();
+		let $misPwd = $('#misPwd');
+		let $avlConPwd = $('#avlConPwd');
+		let $btnSavePassword = $('#btnSavePassword');
+
+		if (fnValidationPwdSameConfirmPwd(password, confirmPassword)) {
+			$avlConPwd.hide();
+			$misPwd.show();
+			$btnSavePassword.attr('disabled', true);
+		} else {
+			$misPwd.hide();
+			$avlConPwd.show();
+			$btnSavePassword.attr('disabled', false);
+		}
+
+	};
+
+	// 패스워드 저장
+	$('#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();
+		fnCheckConfirmPassword();
+		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>

+ 307 - 0
src/main/webapp/WEB-INF/views/web/customer/PasswordFindFormWeb.html

@@ -0,0 +1,307 @@
+<!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  : IdFindFormWeb.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" minlength="4" maxlength="12"/>
+															<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="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/password/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') {
+			cfnGoToPage(_PAGE_CUSTOMER_PWD_CHANGE_FIND);
+		}
+	};
+
+	// 찾기실패
+	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/password/find/certify', jsonData, fnInfoConfirmCallBack)
+		}
+	};
+
+/*]]>*/
+</script>
+
+</th:block>
+
+</body>
+</html>

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

@@ -0,0 +1,398 @@
+<!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" onclick="fnDeleteOrder()"><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')}">
+								<input type="hidden" name="ordDtlNo" th:value="${order.ordDtlNo}"/>
+								<input type="hidden" name="ordDtlStat" th:value="${order.ordDtlStat}"/>
+								<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" th:if="${order.ordDtlStatBanner == 'Y'}">
+									<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'}" onclick="fnDecideOrder(this);">구매확정 하기</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">
+	let ordNo = [[${ordNo}]];
+	
+	// 주문 내역 삭제 처리
+	var fnDeleteOrder = function() {
+		mcxDialog.confirm('주문 내역을 삭제하시겠습니까?', {
+			cancelBtnText: "취소",
+			sureBtnText: "확인",
+			sureBtnClick: function(){
+				let data = {};
+				
+				data.ordNo = ordNo;
+				
+				var jsonData = JSON.stringify(data);
+				gagajf.ajaxJsonSubmit('/mypage/order/delete'
+					, jsonData
+					, function() {
+						cfnGoToPage(_PAGE_MYPAGE);
+					});
+			}
+		});
+	};
+	
+	// 구매확정 처리
+	var fnDecideOrder = function(param) {
+		let ordDtlNoArr = $(param).parent().parent().find('input[name=ordDtlNo]');
+		let ordDtlStatArr = $(param).parent().parent().find('input[name=ordDtlStat]');
+		
+		console.log(ordDtlNoArr);
+		let orderDecisionArr = [];
+		$.each(ordDtlNoArr, function(idx, item) {
+			console.log(item.value);
+			if (ordDtlStatArr[idx].value == 'G013_60') {
+				orderDecisionArr.push(item.value);
+			}
+		});
+
+		console.log(orderDecisionArr);
+		if (orderDecisionArr.length == 0) {
+			mcxDialog.alert('구매확정 가능한 상품이 없습니다.');
+			return false;
+		}
+
+		mcxDialog.confirm('구매확정 처리를 하시겠습니까?', {
+			cancelBtnText: "취소",
+			sureBtnText: "확인",
+			sureBtnClick: function(){
+				let data = {};
+				
+				data.ordNo = ordNo;
+				data.ordDtlNoArr = orderDecisionArr;
+				
+				var jsonData = JSON.stringify(data);
+				gagajf.ajaxJsonSubmit('/mypage/order/decision'
+					, jsonData
+					, function() {
+						cfnGoToPage(_PAGE_ORDER_DETAIL + ordNo);
+					});
+			}
+		});
+	}
+
+	$(document).ready(function() {
+		// 마이페이지 LNB 설정
+		fnSetMypageLnbList(1);
+		
+		// 마이페이지 location 설정
+		fnSetMypageLocation('주문확인/배송조회', '_PAGE_ORDER_LIST', '주문상세');
+	});
+	
+</script>
+
+</th:block>
+
+</body>
+</html>

+ 45 - 100
src/main/webapp/WEB-INF/views/web/mypage/MypageOrderListFormWeb.html

@@ -51,33 +51,34 @@
 			<!-- 주문 경로 -->
 			<div class="order_info clear">
 				<ul class="clear">
-					<li class="orl01">
+					<li>
 						<p class="or_p">주문접수</p>
 						<p class="count"><span th:text="${orderReceiptCount}">0</span></p>
 					</li>
-					<li class="orl02">
+					<li>
 						<p class="or_p">결제완료</p>
 						<p class="count"><span th:text="${paymentCompleteCount}">0</span></p>
 					</li>
-					<li class="orl03">
+					<li>
 						<p class="or_p">상품 준비 중</p>
 						<p class="count"><span th:text="${goodsPrepareCount}">0</span></p>
 					</li>
-					<li class="orl04">
+					<li>
+						<p class="or_p">배송 준비 중</p>
+						<p class="count"><span th:text="${shipPrepareCount}">0</span></p>
+					</li>
+					<li>
 						<p class="or_p">배송 중</p>
 						<p class="count"><span th:text="${shippingCount}">0</span></p>
 					</li>
-					<li class="orl05">
+					<li>
 						<p class="or_p">배송 완료</p>
 						<p class="count"><span th:text="${shipCompleteCount}">0</span></p>
 					</li>
 				</ul>
 				<div class="order_right">
-					<ul>
-						<li>취소 내역<span th:text="${cancelCount}">0</span></li>
-						<li>교환 내역<span th:text="${returnCount}">0</span></li>
-						<li>반품 내역<span th:text="${exchangeCount}">0</span></li>
-					</ul>
+					<p class="or_p">취소/교환/반품</p>
+					<p class="count"><span th:text="${cancelCount + returnCount + exchangeCount}">0</span></p>
 				</div>
 			</div>
 			<!-- //주문 경로 -->
@@ -85,20 +86,19 @@
 			<!-- 주문조회 검색 -->
 			<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>-->
+					<input type="checkbox" name="month" value="최근 1개월" id="chk01" onclick="fnSetSearchPeriod(1);">
+					<label for="chk01">최근 1개월</label>
+					<input type="checkbox" name="month" value="최근 3개월" id="chk02" onclick="fnSetSearchPeriod(3);">
+					<label for="chk02">최근 2개월</label>
+					<input type="checkbox" name="month" value="최근 6개월" id="chk03" onclick="fnSetSearchPeriod(6);">
+					<label for="chk03">최근 3개월</label>
 				</div>
 				<div class="sch_right">
 					<div class="sch_datepicker sb">
-						<input type="text" class="n_input hasDatepicker" name="dt_fr_input" value="" placeholder="20.10.05" id="">
+						<input type="text" class="n_input my_datepicker" name="stDate" value="" th:placeholder="${#calendars.format(#calendars.createNow(), 'yyyy-MM-dd')}" id="stDate">
 					</div>
 					<div class="sch_datepicker">
-						<input type="text" class="n_input hasDatepicker" name="dt_to_input" value="" placeholder="20.10.05" id="">
+						<input type="text" class="n_input my_datepicker" name="edDate" value="" th:placeholder="${#calendars.format(#calendars.createNow(), 'yyyy-MM-dd')}" id="edDate">
 					</div>
 					<button type="button" class="btn btn_dark">조회</button>
 				</div>
@@ -116,11 +116,11 @@
 							<span class="order_date" th:text="${oneData.ordDt}"></span>
 
 							<!-- 배송구분 설정 -->
-							<span class="order_method" th:if="${oneData.shotDelvYn == 'Y'}" th:text="총알배송"></span>
-							<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>
+							<span class="order_method" th:if="${oneData.shotDelvYn == 'Y'}">총알배송</span>
+							<span class="order_method" th:if="${oneData.shotDelvYn == 'N' and oneData.selfGoodsYn == 'Y'}">일반배송</span>
+							<span class="order_method" th:if="${oneData.selfGoodsYn == 'N'}">업체직배송</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 +130,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 +172,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">주소 입력 대기</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">선물 완료</p>
 															<p class="dlvr_desc" th:text="|(${order.giftCompleteDt})|"></p>
 														</th:block>
 													</th:block>
@@ -210,10 +210,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>
@@ -232,11 +228,11 @@
 															<button type="button" class="btn btn_primary">구매확정 하기</button>
 														</div>
 														<div class="order_confirm" th:if="${order.ordDtlStat == 'G013_70' and order.reviewSq == 0}">
-															<span class="cf_txt" th:text="리뷰를 작성하면 다른 구매자에게 도움이 될 수 있습니다."></span>
+															<span class="cf_txt">리뷰를 작성하면 다른 구매자에게 도움이 될 수 있습니다.</span>
 															<button type="button" class="btn btn_primary">리뷰작성</button>
 														</div>
 														<div class="order_confirm" th:if="${order.ordDtlStat == 'G013_70' and order.reviewSq > 0}">
-															<span class="cf_txt" th:text="주문내역 다시 구매하기 위해"></span>
+															<span class="cf_txt">주문내역 다시 구매하기 위해</span>
 															<button type="button" class="btn btn_primary">장바구니 담기</button>
 														</div>
 													</td>
@@ -254,7 +250,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">주소입력 기한이 경과되어 선물이 취소 되었습니다.</span>
 														</div>
 													</td>
 												</tr>
@@ -271,72 +267,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>
@@ -349,8 +279,23 @@
 		
 		// 마이페이지 location 설정
 		fnSetMypageLocation('주문확인/배송조회');
+		
+		// datepicker 설정
+		$(".my_datepicker").datepicker();
 	});
 	
+	var fnGoToOrderDetail = function(param) {
+		let ordNo = $(param).attr('ordNo');
+		cfnGoToPage(_PAGE_ORDER_DETAIL + ordNo);
+	}
+	
+	var fnSetSearchPeriod = function(period) {
+		let date = new Date();
+		$('#edDate').val(date.getFullYear() + '-' + ('0' + (date.getMonth() + 1)).slice(-2) + '-' + ('0' + (date.getDate() + 1)).slice(-2));
+		date.setMonth(date.getMonth() - period);
+		$('#stDate').val(date.getFullYear() + '-' + ('0' + (date.getMonth() + 1)).slice(-2) + '-' + ('0' + (date.getDate() + 1)).slice(-2));
+	}
+	
 /*]]>*/
 </script>
 

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

@@ -0,0 +1,228 @@
+/**
+ *******************************************************************************
+ * @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");
+};
+
+/**
+ * 비밀번호 길이확인
+ * @param password - 패스워드
+ * @return boolean 패스워드 길이가 짧거나 길면 true
+ * @author jsshin
+ * @since 2021. 02. 17
+ */
+var fnValidationPwdLength = function (password) {
+	let result;
+	// 길이
+	if(!/^[a-zA-Z0-9!@#$%^&*()?_~]{8,20}$/.test(password)) {
+		result = true;
+	} else {
+		result = false;
+	}
+
+	return result;
+};
+
+/**
+ * 비밀번호 영문, 숫자, 특수문자 2종 이상 혼용
+ * @param password - 패스워드
+ * @return boolean 충족이 안되면 true
+ * @author jsshin
+ * @since 2021. 02. 17
+ */
+var fnValidtaionPwdMixedWord = function (password) {
+	let result;
+	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) {
+		result = true;
+	} else {
+		result = false;
+	}
+
+	return result;
+};
+
+
+/**
+ * 동일한 문자 숫자 4자이상 인지확인
+ * @param password - 패스워드
+ * @return boolean 동일한 문자가 있으면 true
+ * @author jsshin
+ * @since 2021. 02. 17
+ */
+var fnValidationPwdSameWord = function (password) {
+	let result;
+	if (/(\w)\1\1\1/.test(password)) {
+		result = true;
+	} else {
+		result = false;
+	}
+	return result;
+};
+
+/**
+ * 연속되는 문자가 4자이상 인지확인
+ * @param password - 패스워드
+ * @return boolean 연속된 문자가 있으면 true
+ * @author jsshin
+ * @since 2021. 02. 17
+ */
+var fnValidtaionPwdCntnsWord = function (password) {
+	let result;
+	let intCnt1 = 0;
+	let intCnt2 = 0;
+	let wordZero = '';
+	let wordOne = '';
+	let wordTwo = '';
+	let wordThree = '';
+
+	for (var i = 0; i < password.length-3; i++) {
+		wordZero = password.charAt(i);
+		wordOne = password.charAt(i + 1);
+		wordTwo = password.charAt(i + 2);
+		wordThree = password.charAt(i + 3);
+
+		if (wordZero.charCodeAt(0) - wordOne.charCodeAt(0) == 1
+			&& wordOne.charCodeAt(0) - wordTwo.charCodeAt(0) == 1
+			&& wordTwo.charCodeAt(0) - wordThree.charCodeAt(0) == 1) {
+			intCnt1 = intCnt1 + 1;
+		}
+
+		if (wordZero.charCodeAt(0) - wordOne.charCodeAt(0) == -1
+			&& wordOne.charCodeAt(0) - wordTwo.charCodeAt(0) == -1
+			&& wordTwo.charCodeAt(0) - wordThree.charCodeAt(0) == -1) {
+			intCnt2 = intCnt2 + 1;
+		}
+	}
+
+	if (intCnt1 > 0 || intCnt2 > 0) {
+		result = true;
+	} else {
+		result = false;
+	}
+	return result;
+}
+
+/**
+ * 비밀번호가 아이디랑 동일한지 확인
+ * @param password - 패스워드
+ * @param custId - 고객아이디
+ * @return boolean 아이디랑 동일한게 있으면 true
+ * @author jsshin
+ * @since 2021. 02. 17
+ */
+var fnValidationPwdSameId = function (password, custId) {
+	let result;
+
+	if (password.search(custId) > -1) {
+		result = true;
+	} else {
+		result = false;
+	}
+	return result;
+}
+
+/**
+ * 확인 비밀번호 유효성 체크
+ * @param password - 비밀번호
+ * @param confirmPassword - 확인 비밀번호
+ * @author jsshin
+ * @since 2021. 02. 17
+ */
+var fnValidationPwdSameConfirmPwd = function (password, confirmPassword) {
+	let result;
+	if (password != confirmPassword) {
+		result = true;
+	} else {
+		result = false;
+	}
+	return result;
+};
+
+
+
+/*
+* 임시사용
+*
+* */
+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

+ 71 - 8
src/main/webapp/ux/style24_link.js

@@ -8,13 +8,14 @@ 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";	// 고객 > 비밀번호 찾기 > 결과페이지
+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_PWD_FIND = _frontUrl + "/customer/password/find/form";							// 고객 > 비밀번호 찾기
+const _PAGE_CUSTOMER_PWD_CHANGE_FIND = _frontUrl + "/customer/password/change/form?pageGb=find";	// 고객 > 비밀번호 찾기> 비밀번호 변경 화면
+const _PAGE_CUSTOMER_PWD_CHANGE_TEMP = _frontUrl + "/customer/password/change/form?pageGb=temp";	// 고객 > 임시비밀번호 로그인 > 비밀번호 변경 화면
+const _PAGE_CUSTOMER_DORMANT = _frontUrl + "/customer/dormant/certify/form";						// 고객 > 휴면회원
 
 //== 상품상세 ==/
 
@@ -25,7 +26,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 +66,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 = 420;
+	var popupHeight = 720;
+	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 = 445;
+	var popupHeight = 550;
+	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;
+		}
+	}
+};