Prechádzať zdrojové kódy

Merge branch 'develop' into order

card007 5 rokov pred
rodič
commit
086788df1a

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

@@ -4,7 +4,6 @@ import java.io.IOException;
 import java.math.BigInteger;
 import java.security.SecureRandom;
 
-import javax.servlet.RequestDispatcher;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import javax.servlet.http.HttpSession;
@@ -13,7 +12,6 @@ import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.core.env.Environment;
 import org.springframework.stereotype.Controller;
-import org.springframework.web.HttpRequestMethodNotSupportedException;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestParam;
@@ -34,7 +32,6 @@ import com.style24.persistence.domain.Customer;
 import lombok.extern.slf4j.Slf4j;
 
 import com.gagaframework.web.parameter.GagaMap;
-import com.gagaframework.web.rest.server.GagaResponseStatus;
 
 /**
  * Index Controller
@@ -67,51 +64,66 @@ public class TsfIndexController extends TsfBaseController {
 	@Autowired
 	private ObjectMapper objectMapper;
 
+//	/**
+//	 * 에러 페이지
+//	 * @return
+//	 * @author gagamel
+//	 * @throws IOException
+//	 * @since 2020. 3. 18
+//	 */
+//	@GetMapping("/error")
+//	public ModelAndView error(HttpServletRequest request, HttpServletResponse response) throws HttpRequestMethodNotSupportedException, IOException {
+//		ModelAndView mav = new ModelAndView();
+//
+//		Object status = request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE);
+//
+//		if (status != null) {
+//			Integer statusCode = Integer.valueOf(status.toString());
+//			log.info("statusCode: {}", statusCode);
+//
+//			if (statusCode == GagaResponseStatus.NOT_FOUND.getCode()) {
+//				mav.addObject("status", GagaResponseStatus.NOT_FOUND.getCode());
+//
+//				// 404 오류 시 잘못된 링크 유입 시 몰메인으로 이동 처리
+//				String prevRequestUri = (String)request.getAttribute(RequestDispatcher.FORWARD_REQUEST_URI);
+//				log.info("prevRequestUri: {}", prevRequestUri);
+//				if (prevRequestUri.startsWith("/m")) {
+//					response.sendRedirect("/");
+//				}
+//
+//				String profiles = env.getProperty("spring.profiles.active").toLowerCase();
+//				if ("locd".equals(profiles) || "locp".equals(profiles) || "dev".equals(profiles)) {
+//					mav.addObject("message", "No mapping found for HTTP request with URI ["
+//						+ String.valueOf(request.getAttribute(RequestDispatcher.FORWARD_REQUEST_URI)) + "]");
+//				}
+//
+//				mav.setViewName(super.getDeviceViewName("error/404"));
+//
+//				return mav;
+//			}
+//		}
+//
+//		mav.addObject("status", GagaResponseStatus.INTERNAL_SERVER_ERROR.getCode());
+//
+//		String profiles = env.getProperty("spring.profiles.active").toLowerCase();
+//		if ("locd".equals(profiles) || "locp".equals(profiles) || "dev".equals(profiles)) {
+//			mav.addObject("message", String.valueOf(request.getAttribute(RequestDispatcher.ERROR_MESSAGE)));
+//		}
+//
+//		mav.setViewName(super.getDeviceViewName("error/500"));
+//
+//		return mav;
+//	}
+
 	/**
-	 * 에러 페이지
+	 * 시스템점검중 페이지
 	 * @return
 	 * @author gagamel
-	 * @throws IOException
-	 * @since 2020. 3. 18
+	 * @since 2020. 3. 29
 	 */
-	@GetMapping("/error")
-	public ModelAndView error(HttpServletRequest request, HttpServletResponse response) throws HttpRequestMethodNotSupportedException, IOException {
-		ModelAndView mav = new ModelAndView(super.getDeviceViewName("error/500"));
-
-		Object status = request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE);
-
-		if (status != null) {
-			Integer statusCode = Integer.valueOf(status.toString());
-			log.info("statusCode: {}", statusCode);
-
-			if (statusCode == GagaResponseStatus.NOT_FOUND.getCode()) {
-				mav.addObject("status", GagaResponseStatus.NOT_FOUND.getCode());
-
-				// 404 오류 시 잘못된 링크 유입 시 몰메인으로 이동 처리
-				String prevRequestUri = (String)request.getAttribute(RequestDispatcher.FORWARD_REQUEST_URI);
-				log.info("prevRequestUri: {}", prevRequestUri);
-				if (prevRequestUri.startsWith("/m")) {
-					response.sendRedirect("/");
-				}
-
-				String profiles = env.getProperty("spring.profiles.active").toLowerCase();
-				if ("locd".equals(profiles) || "locp".equals(profiles) || "dev".equals(profiles)) {
-					mav.addObject("message", "No mapping found for HTTP request with URI ["
-						+ String.valueOf(request.getAttribute(RequestDispatcher.FORWARD_REQUEST_URI)) + "]");
-				}
-
-				return mav;
-			}
-		}
-
-		mav.addObject("status", GagaResponseStatus.INTERNAL_SERVER_ERROR.getCode());
-
-		String profiles = env.getProperty("spring.profiles.active").toLowerCase();
-		if ("locd".equals(profiles) || "locp".equals(profiles) || "dev".equals(profiles)) {
-			mav.addObject("message", String.valueOf(request.getAttribute(RequestDispatcher.ERROR_MESSAGE)));
-		}
-
-		return mav;
+	@GetMapping("/system/check")
+	public String systemCheck() {
+		return super.getDeviceViewName("error/SystemCheck");
 	}
 
 	/**

+ 10 - 2
src/main/java/com/style24/front/biz/web/TsfPlanningController.java

@@ -3,6 +3,7 @@ package com.style24.front.biz.web;
 import java.util.Collection;
 
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.mobile.device.Device;
 import org.springframework.stereotype.Controller;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PostMapping;
@@ -74,18 +75,24 @@ public class TsfPlanningController extends TsfBaseController {
 	/**
 	 * 기획전 메인 목록
 	 * @param plan - 기획전 정보
+	 * @param device - 디바이스 정보
 	 * @return
 	 * @author gagamel
 	 * @since 2021. 3. 29
 	 */
 	@GetMapping("/main/list")
 	@ResponseBody
-	public Collection<Plan> getPlanningMainList(Plan plan) {
+	public Collection<Plan> getPlanningMainList(Plan plan, Device device) {
 		plan.setSiteCd(TscConstants.Site.STYLE24.value());
 		plan.setFrontGb(TsfSession.getFrontGb());
 		plan.setCustGb(TsfSession.getCustGb());
 		plan.setCustNo(TsfSession.isLogin() ? TsfSession.getInfo().getCustNo() : 0);
-		plan.setMaxRow(2);
+
+		if (device.isNormal()) {
+			plan.setMaxRow(2); // PC웹은 2개
+		} else {
+			plan.setMaxRow(3); // 모바일은 3개
+		}
 
 		return planningService.getPlanningMainList(plan);
 	}
@@ -130,6 +137,7 @@ public class TsfPlanningController extends TsfBaseController {
 		plan.setCustNo(TsfSession.isLogin() ? TsfSession.getInfo().getCustNo() : 0);
 		
 		// 기본 set
+		plan.setExceptPlanSq(planSq);
 		plan.setPlanSq(planSq);
 		review.setPlanSq(planSq);
 		coupon.setPlanSq(planSq);

+ 74 - 86
src/main/java/com/style24/front/support/controller/TsfBaseController.java

@@ -1,7 +1,5 @@
 package com.style24.front.support.controller;
 
-import java.sql.SQLException;
-import java.sql.SQLRecoverableException;
 import java.util.Collection;
 import java.util.Set;
 
@@ -11,9 +9,6 @@ import javax.validation.Validation;
 import javax.validation.Validator;
 
 import org.apache.commons.lang3.StringUtils;
-import org.apache.commons.lang3.exception.ExceptionUtils;
-import org.apache.ibatis.binding.BindingException;
-import org.springframework.beans.TypeMismatchException;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.propertyeditors.StringTrimmerEditor;
 import org.springframework.core.env.Environment;
@@ -22,15 +17,9 @@ import org.springframework.mobile.device.DeviceUtils;
 import org.springframework.mobile.device.site.SitePreference;
 import org.springframework.mobile.device.site.SitePreferenceUtils;
 import org.springframework.mobile.device.util.ResolverUtils;
-import org.springframework.security.access.AccessDeniedException;
 import org.springframework.util.Assert;
-import org.springframework.validation.FieldError;
-import org.springframework.web.HttpRequestMethodNotSupportedException;
-import org.springframework.web.bind.MethodArgumentNotValidException;
-import org.springframework.web.bind.MissingServletRequestParameterException;
 import org.springframework.web.bind.WebDataBinder;
 import org.springframework.web.bind.annotation.ControllerAdvice;
-import org.springframework.web.bind.annotation.ExceptionHandler;
 import org.springframework.web.bind.annotation.InitBinder;
 import org.springframework.web.bind.annotation.ModelAttribute;
 import org.springframework.web.bind.annotation.ResponseBody;
@@ -38,7 +27,6 @@ import org.springframework.web.context.request.RequestAttributes;
 import org.springframework.web.context.request.RequestContextHolder;
 import org.springframework.web.context.request.ServletRequestAttributes;
 
-import com.fasterxml.jackson.databind.JsonMappingException;
 import com.style24.core.support.message.TscMessageByLocale;
 import com.style24.front.support.env.TsfConstants;
 import com.style24.front.support.security.session.TsfSession;
@@ -195,80 +183,80 @@ public class TsfBaseController {
 		return GagaResponse.error(GagaResponseStatus.FAIL.getCode(), message);
 	}
 
-	@ExceptionHandler(AccessDeniedException.class)
-	@ResponseBody
-	public GagaResponse handleForbidden(Exception e) {
-		return GagaResponse.error(GagaResponseStatus.FORBIDDEN.getCode(), e.getMessage());
-	}
-
-	@ExceptionHandler(TypeMismatchException.class)
-	@ResponseBody
-	public GagaResponse handleBadRequestException(Exception e) {
-		errorLogging(e);
-		return GagaResponse.error(GagaResponseStatus.BAD_REQUEST.getCode(), e.getMessage());
-	}
-
-	@ExceptionHandler(MissingServletRequestParameterException.class)
-	@ResponseBody
-	public GagaResponse handleRequestParameterException(MissingServletRequestParameterException e) {
-		errorLogging(e);
-		return GagaResponse.error(GagaResponseStatus.BAD_REQUEST.getCode(), e.getMessage());
-	}
-
-	/**
-	 * HttpRequestMethodNotSupportedException Handler
-	 * @param e - HttpRequestMethodNotSupportedException, SQLRecoverableException
-	 * @return forwarding URI
-	 */
-	@ExceptionHandler({HttpRequestMethodNotSupportedException.class, SQLRecoverableException.class})
-	public String handleException(HttpRequestMethodNotSupportedException e) {
-		return "forward:/error/500";
-	}
-
-	@ExceptionHandler(Throwable.class)
-	@ResponseBody
-	public GagaResponse handleException(Throwable throwable) {
-		errorLogging(throwable);
-
-		Throwable rootCause = ExceptionUtils.getRootCause(throwable);
-
-		if (rootCause != null) {
-			throwable = rootCause;
-		}
-
-		if (throwable instanceof SQLException || throwable instanceof BindingException ||
-			throwable instanceof JsonMappingException) {
-			String message = String.format("데이터 처리중 에러가 발생하였습니다. 시스템 관리자에게 문의하세요.");
-			return GagaResponse.error(GagaResponseStatus.INTERNAL_SERVER_ERROR.getCode(), message);
-		}
-
-		return GagaResponse.error(GagaResponseStatus.INTERNAL_SERVER_ERROR.getCode(), throwable.getMessage());
-	}
-
-	private void errorLogging(Throwable throwable) {
-		if (log.isErrorEnabled()) {
-			Throwable rootCause = ExceptionUtils.getRootCause(throwable);
-
-			if (rootCause != null) {
-				throwable = rootCause;
-			}
-
-			if (throwable.getMessage() != null) {
-				log.error(throwable.getMessage(), throwable);
-			} else {
-				log.error("ERROR", throwable);
-			}
-		}
-	}
-
-	@ExceptionHandler(MethodArgumentNotValidException.class)
-	@ResponseBody
-	public Object processValidationError(MethodArgumentNotValidException ex) {
-		FieldError fieldError = ex.getBindingResult().getFieldErrors().get(0);
-		GagaResponse error = GagaResponse.error(GagaResponseStatus.INTERNAL_SERVER_ERROR.getCode(), fieldError.getDefaultMessage());
-		error.getError().setRequiredKey(fieldError.getField());
-		return error;
-	}
+//	@ExceptionHandler(AccessDeniedException.class)
+//	@ResponseBody
+//	public GagaResponse handleForbidden(Exception e) {
+//		return GagaResponse.error(GagaResponseStatus.FORBIDDEN.getCode(), e.getMessage());
+//	}
+//
+//	@ExceptionHandler(TypeMismatchException.class)
+//	@ResponseBody
+//	public GagaResponse handleBadRequestException(Exception e) {
+//		errorLogging(e);
+//		return GagaResponse.error(GagaResponseStatus.BAD_REQUEST.getCode(), e.getMessage());
+//	}
+//
+//	@ExceptionHandler(MissingServletRequestParameterException.class)
+//	@ResponseBody
+//	public GagaResponse handleRequestParameterException(MissingServletRequestParameterException e) {
+//		errorLogging(e);
+//		return GagaResponse.error(GagaResponseStatus.BAD_REQUEST.getCode(), e.getMessage());
+//	}
+//
+//	/**
+//	 * HttpRequestMethodNotSupportedException Handler
+//	 * @param e - HttpRequestMethodNotSupportedException, SQLRecoverableException
+//	 * @return forwarding URI
+//	 */
+//	@ExceptionHandler({HttpRequestMethodNotSupportedException.class, SQLRecoverableException.class})
+//	public String handleException(HttpRequestMethodNotSupportedException e) {
+//		return "forward:/error";
+//	}
+//
+//	@ExceptionHandler(Throwable.class)
+//	@ResponseBody
+//	public GagaResponse handleException(Throwable throwable) {
+//		errorLogging(throwable);
+//
+//		Throwable rootCause = ExceptionUtils.getRootCause(throwable);
+//
+//		if (rootCause != null) {
+//			throwable = rootCause;
+//		}
+//
+//		if (throwable instanceof SQLException || throwable instanceof BindingException ||
+//			throwable instanceof JsonMappingException) {
+//			String message = String.format("데이터 처리중 에러가 발생하였습니다. 시스템 관리자에게 문의하세요.");
+//			return GagaResponse.error(GagaResponseStatus.INTERNAL_SERVER_ERROR.getCode(), message);
+//		}
+//
+//		return GagaResponse.error(GagaResponseStatus.INTERNAL_SERVER_ERROR.getCode(), throwable.getMessage());
+//	}
+//
+//	private void errorLogging(Throwable throwable) {
+//		if (log.isErrorEnabled()) {
+//			Throwable rootCause = ExceptionUtils.getRootCause(throwable);
+//
+//			if (rootCause != null) {
+//				throwable = rootCause;
+//			}
+//
+//			if (throwable.getMessage() != null) {
+//				log.error(throwable.getMessage(), throwable);
+//			} else {
+//				log.error("ERROR", throwable);
+//			}
+//		}
+//	}
+//
+//	@ExceptionHandler(MethodArgumentNotValidException.class)
+//	@ResponseBody
+//	public Object processValidationError(MethodArgumentNotValidException ex) {
+//		FieldError fieldError = ex.getBindingResult().getFieldErrors().get(0);
+//		GagaResponse error = GagaResponse.error(GagaResponseStatus.INTERNAL_SERVER_ERROR.getCode(), fieldError.getDefaultMessage());
+//		error.getError().setRequiredKey(fieldError.getField());
+//		return error;
+//	}
 
 	/**
 	 * Custom Validation using group class

+ 76 - 15
src/main/java/com/style24/front/support/controller/TsfCustomErrorController.java

@@ -1,32 +1,93 @@
 package com.style24.front.support.controller;
 
-import org.springframework.boot.web.servlet.error.ErrorController;
+import java.io.IOException;
+import java.util.Map;
+
+import javax.servlet.RequestDispatcher;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.springframework.boot.autoconfigure.web.servlet.error.AbstractErrorController;
+import org.springframework.boot.web.error.ErrorAttributeOptions;
+import org.springframework.boot.web.servlet.error.ErrorAttributes;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
 import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.servlet.ModelAndView;
+
+import lombok.extern.slf4j.Slf4j;
 
 /**
  * Custom Error Controller
- * 		1. Disabling the Whitelabel Error Page
- * 			- application.yml 파일에 다음을 추가
- * 				server.error.whitelabel.enabled=false
- * 			
- * 			or
- * 
- * 			- ~Application.java 파일에 다음을 추가
- * 				@EnableAutoConfiguration(exclude = {ErrorMvcAutoConfiguration.class})
- * 
- * 		2. Create a Custom ErrorController
- * 			you have to create a class that implements the ErrorController interface.
- * 			And overrides its getErrorPath() to return a custom path to call when an error occurred.
+ * 		Disabling the Whitelabel Error Page
+ * 		- application.yml 파일에 다음을 추가
+ * 			server.error.path='/error'
+ * 			server.error.whitelabel.enabled=false
  * 
  * @author gagamel
  * @since 2020. 9. 11
  */
 @Controller
-public class TsfCustomErrorController implements ErrorController {
+@RequestMapping("${server.error.path:${error.path:/error}}")
+@Slf4j
+public class TsfCustomErrorController extends AbstractErrorController {
+
+	public TsfCustomErrorController(ErrorAttributes errorAttributes) {
+		super(errorAttributes);
+	}
 
 	@Override
 	public String getErrorPath() {
-		return "/error";
+		return this.getErrorPath();
+	}
+
+	/**
+	 * HTML로 응답을 주는 경우의 처리
+	 * @param request - HttpServletRequest
+	 * @param response - HttpServletResponse
+	 * @return
+	 * @throws IOException
+	 */
+	@RequestMapping(produces = MediaType.TEXT_HTML_VALUE)
+	public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) throws IOException {
+		HttpStatus status = this.getStatus(request);
+		log.error("status.value(): {}", status.value());
+
+		Map<String, Object> model = this.getErrorAttributes(request, ErrorAttributeOptions.defaults());
+
+		response.setStatus(status.value());
+		ModelAndView mav = this.resolveErrorView(request, response, status, model);
+
+		if (status.value() == HttpStatus.NOT_FOUND.value()) {
+			return (mav != null) ? mav : new ModelAndView("mob/error/404Mob", model);
+		}
+
+		Object oExceptionType = request.getAttribute(RequestDispatcher.ERROR_EXCEPTION_TYPE);
+		if (oExceptionType != null) {
+			String exceptionType = oExceptionType.toString();
+			log.error("ERROR_EXCEPTION_TYPE: {}", exceptionType);
+
+			// Thymeleaf의 HTML 파일을 못 찾는 에러는 "org.thymeleaf.exceptions.TemplateInputException"임.
+			if (exceptionType.endsWith("org.thymeleaf.exceptions.TemplateInputException")) {
+				return (mav != null) ? mav : new ModelAndView("mob/error/404Mob", model);
+			}
+		}
+
+		return (mav != null) ? mav : new ModelAndView("mob/error/500Mob", model);
+	}
+
+	/**
+	 * HTML 외의 응답이 필요한 경우의 처리
+	 * @param request - HttpServletRequest
+	 * @return
+	 */
+	@RequestMapping
+	public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
+		Map<String, Object> body = this.getErrorAttributes(request, ErrorAttributeOptions.defaults());
+		HttpStatus status = this.getStatus(request);
+		return new ResponseEntity<>(body, status);
 	}
 
 }

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

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

+ 3 - 2
src/main/java/com/style24/persistence/domain/Plan.java

@@ -302,7 +302,8 @@ public class Plan extends TscBaseDomain {
 
 	Collection<Plan> planningGoodsList;	//베너별 상품목록
 
-	private String likeIt;	// 위시리스트담은상품
-	private int maxRow;		// 최대ROW수
+	private String likeIt;			// 위시리스트담은상품
+	private int maxRow;				// 최대ROW수
+	private Integer exceptPlanSq;	// 제외할기획전번호
 
 }

+ 3 - 0
src/main/java/com/style24/persistence/mybatis/shop/TsfPlanning.xml

@@ -114,6 +114,9 @@
 		                             AND    DISP_YN = 'Y' /*전시하는브랜드기획전*/
 		                            )
 		        </if>
+		        <if test="exceptPlanSq != null and exceptPlanSq != ''"> <!-- 제외할기획전 -->
+		        AND    P.PLAN_SQ != #{exceptPlanSq}
+		        </if>
 		       ) Z
 		ORDER  BY NEW_YN DESC, END_DAYS
 	</select>

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

@@ -17,13 +17,14 @@ spring:
             repositories:
                 enabled: true
 
-#server:
+server:
 #    servlet:
 #        session:
 #            cookie:
 #                name: WSESSIONID
 #                secure: true
-#    error.whitelabel.enabled: false
+    error.path: '/error' # 오류 응답을 처리할 Handler의 경로
+    error.whitelabel.enabled: false
 
 # 본인인증
 certify:

+ 2 - 0
src/main/webapp/WEB-INF/views/mob/common/fragments/HeadMob.html

@@ -51,6 +51,8 @@
 	<link rel="icon" href="/images/favicon-16x16.png" sizes="16x16" type="image/png"/>
 	
 	<link rel="stylesheet" type="text/css" href="/ux/mo/css/swiper.min.css"/>
+	<link rel="stylesheet" type="text/css" th:href="@{'/ux/mo/css/common_m.css?v=' + ${#calendars.format(#calendars.createNow(), 'yyyyMMddHHmmss')}}" href="/ux/mo/css/common_m.css"/>
+	<link rel="stylesheet" type="text/css" th:href="@{'/ux/mo/css/layout_m.css?v=' + ${#calendars.format(#calendars.createNow(), 'yyyyMMddHHmmss')}}" href="/ux/mo/css/layout_m.css"/>
 	<link rel="stylesheet" type="text/css" th:href="@{'/ux/mo/css/style24_m.css?v=' + ${#calendars.format(#calendars.createNow(), 'yyyyMMddHHmmss')}}" href="/ux/mo/css/style24_m.css"/>
 	
 	<script src="/ux/mo/js/jquery-3.5.1.min.js"></script>

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 39 - 0
src/main/webapp/WEB-INF/views/mob/error/404Mob.html


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 39 - 0
src/main/webapp/WEB-INF/views/mob/error/SystemCheckMob.html


+ 129 - 0
src/main/webapp/WEB-INF/views/mob/planning/PlanningMainFormMob.html

@@ -0,0 +1,129 @@
+<!DOCTYPE html>
+<html lang="ko"
+	xmlns:th="http://www.thymeleaf.org"
+	xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
+	layout:decorator="mob/common/layout/DefaultLayoutMob">
+<!--
+ *******************************************************************************
+ * @source  : PlanningMainFormMob.html
+ * @desc    : 기획전메인 Page
+ *============================================================================
+ * STYLE24
+ * Copyright(C) 2020 TSIT, All rights reserved.
+ *============================================================================
+ * VER  DATE         AUTHOR      DESCRIPTION
+ * ===  ===========  ==========  =============================================
+ * 1.0  2021.03.29   gagamel     최초 작성
+ *******************************************************************************
+ -->
+<body>
+
+<th:block layout:fragment="content">
+	<!--  container -->
+	<div id="container" class="container dp">
+		<section class="content dp_exhibition">
+			<div class="inner wide">
+				<div class="category_nav">
+					<ul>
+						<li><button type="button" th:class="${cateNo == null ? 'active' : ''}" onclick="cfnGoToPage(_PAGE_PLANNING_MAIN);">전체</button></li>
+						<li><button type="button" th:each="oneData, stat : ${cateList}" th:class="${oneData.cateNo == cateNo ? 'active' : '' }" th:onclick="|cfnGoToPage(_PAGE_PLANNING_MAIN + '?cateNo=${oneData.cateNo}');|">[[${oneData.cateNm}]]</button></li>
+					</ul>
+				</div>
+			</div>
+			<div class="inner">
+				<div class="list_content"> <!-- 데이터 없을시 클래스 nodata 추가 -->
+					<div class="count_wrap">
+						<div>
+							<p id="planningTotCnt"></p>
+						</div>
+					</div>
+					<div class="list_defult nodata" style="display: none;" id="divPlanningNoData">
+						<div>
+							<p>등록된 기획전이 없습니다.</p>
+						</div>
+						<button type="button" class="btn btn_default" onclick="cfnGoToPage(_PAGE_MAIN);"><span>홈으로 가기</span></button>
+					</div>
+					<div class="list_item" style="display: none;" id="divPlanningList">
+					</div>
+				</div>
+			</div>
+		</section>
+	</div>
+	<!-- // container -->
+
+<script th:inline="javascript">
+/*<![CDATA[*/
+	let fnGetPlanningList = function(cateNo) {
+		let actionUrl = '/planning/main/list';
+		if (!gagajf.isNull(cateNo)) actionUrl += '?cateNo=' + cateNo;
+		
+		$.getJSON(actionUrl
+			, function(result, status) {
+				if (status == 'success') {
+					if (result.length > 0) {
+						$('#planningTotCnt').html('<span>' + result.length.addComma() + '</span>개의 기획전');
+						
+						$('#divPlanningList').html('');
+						
+						$.each(result, function(idx, item) {
+							let tag = '<div>\n';
+							tag += '	<div class="visual">\n';
+							
+							if (item.newYn == 'Y') {
+								tag += '		<div class="shape ranker"><span>NEW</span></div>\n';
+							}
+							
+							tag += '		<div class="img">\n';
+							tag += '			<img src="' + _uploadImageUrl + item.mainImg + '" alt="">\n';
+							tag += '		</div>\n';
+							tag += '		<div class="txtWrap">\n';
+							tag += '			<p>' + item.planNm + '</p>\n';
+							tag += '			<p class="txt_xs">' + item.dtlTitle1 + '</p>\n';
+							tag += '		</div>\n';
+							tag += '	</div>\n';
+							
+							if (item.planningGoodsList.length > 0) {
+								tag += '	<div class="itemsGrp n3">\n';
+							
+								$.each(item.planningGoodsList, function(idx2, goods) {
+									tag += '		<div class="item_prod">\n';
+									tag += '			<div class="item_state">\n';
+									tag += '				<a class="itemLink" href="javascript:void(0);" class="itemLink" onclick="cfnGoToGoodsDetail(\'' + goods.goodsCd + '\');">\n';
+									tag += '					<div class="itemPic">\n';
+									tag += '						<img alt="BLUE-a" class=" vLHTC pd_img" src="' + _uploadGoodsUrl + '/' + goods.sysImgNm + '"/>\n';
+									tag += '					</div>\n';
+									tag += '					<div class="itemName">' + goods.goodsNm + '</div>\n';
+									tag += '					<p class="itemPrice">' + goods.currPrice.addComma() + '</p>\n';
+									tag += '				</a>\n';
+									tag += '			</div>\n';
+									tag += '		</div>\n';
+								});
+								
+								tag += '	</div>\n';
+							}
+							
+							tag += '</div>\n';
+							
+							$('#divPlanningList').append(tag);
+						});
+						
+						$('#divPlanningNoData').hide();
+						$('#divPlanningList').show();
+					} else {
+						$('#divPlanningNoData').show();
+						$('#divPlanningList').hide();
+					}
+				}
+			});
+	}
+	
+	$(document).ready(function() {
+		fnGetPlanningList([[${cateNo}]]);
+	});
+/*]]>*/
+</script>
+
+</th:block>
+
+</body>
+</html>

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 39 - 0
src/main/webapp/WEB-INF/views/web/error/404Web.html


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 39 - 0
src/main/webapp/WEB-INF/views/web/error/SystemCheckWeb.html


+ 37 - 9
src/main/webapp/WEB-INF/views/web/planning/PlanningDetailFormWeb.html

@@ -17,8 +17,9 @@
  -->
 <body>
 	<th:block layout:fragment="content">
+	<script src="https://developers.kakao.com/sdk/js/kakao.min.js"></script>
 		<!--  container -->
-		<div id="container" class="container dp" th:with="frontUrl=${@environment.getProperty('domain.front')}, goodsView=${@environment.getProperty('upload.goods.view')}">
+		<div id="container" class="container dp" th:with="frontUrl=${@environment.getProperty('domain.front')}, goodsView=${@environment.getProperty('upload.goods.view')}, planView=${@environment.getProperty('upload.image.view')}">
 			<div class="breadcrumb">
 				<ul>
 					<li class="bread_home"><a href="javascript:void(0);"
@@ -35,7 +36,19 @@
 						<div>
 							<h3 th:text="${planInfo.planNm}"></h3>
 							<div>
-								<a href="javascript:void(0)">sns share</a>
+								<div class="shareSet">
+										<button class="btn_share" data-name="openShare">공유하기</button>
+										<div class="shareWrap" th:with="stylelUrl=${@environment.getProperty('domain.front')}, imgGoodsUrl=${@environment.getProperty('upload.goods.view')}">
+										<div id="layerShare" class="setShare open">
+											<span>
+												<button type="button" class="kk" th:attr="onclick=|cfnSendToKakao('${stylelUrl+'/planning/detail/form?planSq='+planInfo.planSq}', '${planInfo.planNm}', '${planView+ '/'+planInfo.mainImg}');|"><span>카카오톡</span></button>
+												<button type="button" class="fb" th:attr="onclick=|sendSns('facebook', '${stylelUrl+'/planning/detail/form?planSq='+planInfo.planSq}', '${planInfo.planNm}', '', '');|"><span>페이스북</span></button>
+												<button type="button" class="tw" th:attr="onclick=|sendSns('twitter', '${stylelUrl+'/planning/detail/form?planSq='+planInfo.planSq}', '${planInfo.planNm+ '#style24몰'}', '', '');|"><span>트위터</span></button>
+												<button type="button" class="url btn_copy"><span>URL</span></button>
+											</span>
+										</div>
+									</div>
+								</div>
 							</div>
 						</div>
 					</div>
@@ -193,10 +206,10 @@
 									<div class="swiper-slide">
 										<a th:onclick="cfnGoToPlanDetail([[${PlanData.planSq}]])">
 											<div class="thumb">
-												<img th:src="${@environment.getProperty('domain.image')+PlanData.mainImg}" alt="${PlanData.planNm}">
+												<img th:src="${@environment.getProperty('upload.image.view')+PlanData.mainImg}" alt="${PlanData.planNm}">
 											</div>
 											<div class="txt">
-												<span class="brand" th:if="${PlanData.cnt > 1}" th:text="${PlanData.brand}+' 외'"></span>
+												<!-- <span class="brand" th:if="${PlanData.cnt > 1}" th:text="${PlanData.brand}+' 외'"></span> -->
 												<p class="tit" th:text="${PlanData.planNm}"></p>
 											</div>
 										</a>
@@ -560,6 +573,7 @@ var useInfoCoupon = function (id) {
 		// 화면 전환 필요		
 	}
 
+	
 //세번째 자리 콤마찍기 (숫자만 포함, 소수점자리 구분)
 function comma(num){
 	return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
@@ -570,11 +584,25 @@ function comma(num){
 		<script type="text/javascript">
 	    // 컨텐츠 호출
         $(document).ready( function() {
-            $("#header").load("head.html");
-            $("#footer").load("foot.html");
-        });
-
-        $(document).ready( function() {
+        	
+        	//공유 버튼 토글 
+    		$("button[data-name=openShare]").on("click", function(){
+    			$(this).toggleClass("on").next(".shareWrap").toggleClass("on");
+    			return false;
+    		});
+    		//영역밖 클릭으로 공유토글 닫기
+    		$("body").on('click', function(e) { 
+    			if(!$(".shareWrap.on").parent().has(e.target).length) {
+    				$("button[data-name=openShare]").removeClass("on");
+    				$(".shareWrap").removeClass("on");
+    			};
+    		});
+    		
+    		$('.btn_copy').bind('click', function() {
+    			copyToClipboard();
+    		});
+    		
+        	
             $(window).scroll(function(){
                 var navOffset = $('.item_header').offset().top - $('.bullet_sticky_nav').height();
                 var windScroll = $(window).scrollTop();

+ 3 - 3
src/main/webapp/WEB-INF/views/web/planning/PlanningMainFormWeb.html

@@ -8,19 +8,19 @@
  * @source  : PlanningMainFormWeb.html
  * @desc    : 기획전메인 Page
  *============================================================================
- * Pastelmall
+ * STYLE24
  * Copyright(C) 2020 TSIT, All rights reserved.
  *============================================================================
  * VER  DATE         AUTHOR      DESCRIPTION
  * ===  ===========  ==========  =============================================
- * 1.0  2021.03.5   sowon     최초 작성
+ * 1.0  2021.03.05   sowon       최초 작성
  *******************************************************************************
  -->
 <body>
 
 <th:block layout:fragment="content">
 	<!--  container -->
-	<div id="container" class="container dp" th:with="frontUrl=${@environment.getProperty('domain.front')}, goodsView=${@environment.getProperty('upload.goods.view')}">
+	<div id="container" class="container dp">
 		<div class="breadcrumb"> 
 			<ul>
 				<li class="bread_home"><a href="javascript:void(0);" onclick="cfnGoToPage(_PAGE_MAIN);">홈</a></li>

+ 1 - 1
src/main/webapp/ux/style24_link.js

@@ -338,7 +338,7 @@ var cfnLoginYes24 = function (requestGb, chkRememberMe) {
  */
 var cfnGoToGoodsDetail = function (goodsCd, colorCd, ithrCd, contentsLoc, planDtlSq, rccode ) {
 	var params = goodsCd;
-	if (typeof (ithrCd) != 'colorCd') params += "&colorCd=" + colorCd;
+	if (typeof (colorCd) != 'undefined') params += "&colorCd=" + colorCd;
 	if (typeof (ithrCd) != 'undefined') params += "&ithrCd=" + ithrCd;
 	if (typeof (contentsLoc) != 'undefined' && contentsLoc != "") params += "&contentsLoc=" + contentsLoc;
 	if (typeof (planDtlSq) != 'undefined') params += "&planDtlSq=" + planDtlSq;

Niektoré súbory nie sú zobrazené, pretože je v týchto rozdielových dátach zmenené mnoho súborov