Compare commits
30 Commits
6b22974979
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 5e53f19f2a | |||
| f73751497a | |||
| d590a3ad48 | |||
| 8e61cfa559 | |||
| e31ff954e3 | |||
| 761092c2d7 | |||
| 145e0df564 | |||
| f4545ce91a | |||
| 3df9096eec | |||
| b1a427b435 | |||
| 4a764b8295 | |||
| c0d026f896 | |||
| 84f062c681 | |||
| 7f4aa950be | |||
| 029c45a193 | |||
| 462d8a15de | |||
| bacd1fe401 | |||
| 37174437cf | |||
| a057cf425e | |||
|
|
512c4b2458 | ||
|
|
d4dc0cd46c | ||
|
|
32629ea3be | ||
|
|
0f61856d53 | ||
|
|
575471f28f | ||
|
|
07dfb40876 | ||
|
|
6076210bfb | ||
|
|
fc00a8edfc | ||
|
|
868ccf01b1 | ||
|
|
f6792f44d3 | ||
|
|
aecac1cade |
1
.wiki
Submodule
10
Walkthrough.md
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# MadeU Petit Home - 프로젝트 Walkthrough
|
||||||
|
|
||||||
|
최근 개발 환경 및 시스템에 적용된 주요 변경 사항과 기능 구현 내역을 요약한 문서입니다.
|
||||||
|
|
||||||
|
## 1. 프로젝트 초기 구성
|
||||||
|
- **저장소 클론 및 환경 설정**: Git 리포지토리(`madeu_petit_home`) 초기 클론 작업 및 프론트엔드/백엔드 기본 환경 설정을 수행했습니다.
|
||||||
|
|
||||||
|
## 2. 검색 엔진 최적화(SEO) 반영
|
||||||
|
- **Sitemap 파일 구축**: 구글, 네이버 등 주요 검색 엔진의 크롤링 봇이 웹사이트 내부의 페이지들을 효과적으로 수집하고 노출할 수 있도록 프로젝트 내에 `sitemap.xml` 파일을 생성하여 라우팅 지도를 구축했습니다.
|
||||||
|
- **Open Graph (OG) 태그 적용**: 다이어트 홈 페이지 프로젝트와 동일하게 소셜 미디어 링크 공유 시 올바른 썸네일과 문구가 제공되도록 메타 태그(`og` 속성) 생성을 지원했습니다.
|
||||||
94
rules.md
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
# 프로젝트 코딩 가이드라인 (Java Backend)
|
||||||
|
|
||||||
|
AI 에디터(Agent)는 다음 규칙을 항상 준수하여 코드를 작성하고 수정해야 합니다.
|
||||||
|
|
||||||
|
## 0. 기본 소통 규칙 (Communication)
|
||||||
|
- **언어**: 사용자에 대한 모든 답변과 코드 설명은 항상 **한글(Korean)**로만 작성해야 합니다.
|
||||||
|
|
||||||
|
## 1. 패키지 구성 (Package Structure)
|
||||||
|
- **베이스 패키지**: `com.madeuhome`
|
||||||
|
- **컨트롤러 (Controller)**: `ctrl`
|
||||||
|
- **서비스 (Service)**: `svc`
|
||||||
|
- **DTO (Data Transfer Object)**: `dto`
|
||||||
|
- **매퍼 (Mapper)**: `mapper`
|
||||||
|
- **공통 서비스**: `com.madeuhome.common.service` (LogHistoryService 등 시스템 공통 모듈)
|
||||||
|
|
||||||
|
## 2. 파일 명명 규칙 및 구성 (File Naming Conventions)
|
||||||
|
- **컨트롤러 (Controller)**: `[도메인명]Controller.java` (예: `ABCDController.java`)
|
||||||
|
- **서비스 (Service)**: `[도메인명]Service.java` (인터페이스와 구현체(impl)를 분리하지 않고 Service 클래스 파일 하나로만 구현, 예: `ABCDService.java`)
|
||||||
|
- **DTO**: `[도메인명]DTO.java` (예: `ABCDDTO.java`)
|
||||||
|
- **매퍼 (Mapper)**: `[도메인명]Mapper.java` (예: `ABCDMapper.java`)
|
||||||
|
- **XML Mapper**: `[도메인명]SqlMap.xml` (namespace는 Mapper 인터페이스의 **FQCN**과 반드시 일치)
|
||||||
|
|
||||||
|
## 3. URL 및 메소드 명명 규칙 (RequestMapping & Method Naming)
|
||||||
|
|
||||||
|
### 1) RequestMapping (URL) 및 컨트롤러 메소드명
|
||||||
|
- 페이지 이동하는 url : `moveXXXX.do`
|
||||||
|
- 팝업 오픈하는 url : `openXXXX.do`
|
||||||
|
- 조회 url : `getXXXX.do`
|
||||||
|
- 저장 url : `putXXXX.do`
|
||||||
|
- 수정 url : `modXXXX.do`
|
||||||
|
- 삭제 url : `delXXXX.do`
|
||||||
|
- **단, 컨트롤러 메소드명은 위 url에서 `.do`를 제외한 이름과 동일하게 명명합니다.**
|
||||||
|
|
||||||
|
### 2) 서비스 메소드명
|
||||||
|
- 서비스 메소드명은 **컨트롤러 메소드명과 동일**하게 명명합니다.
|
||||||
|
- 조회: `getXXXX` / 목록 조회: `getXXXXList`
|
||||||
|
- 저장: `putXXXX`
|
||||||
|
- 수정: `modXXXX`
|
||||||
|
- 삭제: `delXXXX`
|
||||||
|
|
||||||
|
### 3) Mapper 인터페이스 메소드명
|
||||||
|
- 단일조회 : `selectXXXX`
|
||||||
|
- 리스트조회 : `selectListXXXX`
|
||||||
|
- insert : `insertXXXX`
|
||||||
|
- update : `updateXXXX`
|
||||||
|
- delete : `deleteXXXX`
|
||||||
|
|
||||||
|
## 4. 데이터베이스 연동 정보 (DB Connection)
|
||||||
|
- `application-local.yml`의 설정을 기반으로 한 공통 접속 정보입니다.
|
||||||
|
- **Host**: 183.98.184.84
|
||||||
|
- **Port**: 3306
|
||||||
|
- **Database**: madeu
|
||||||
|
- **User**: madeu
|
||||||
|
- **Password**: apdlemdb12#$
|
||||||
|
|
||||||
|
## 5. 아키텍처 및 코딩 원칙 (Architecture & Coding Principles)
|
||||||
|
|
||||||
|
### 5-1. 컨트롤러 원칙 (Skinny Controller)
|
||||||
|
- 컨트롤러에는 비즈니스 로직이나 예외처리 로직을 넣지 않고, **서비스 메서드를 호출하는 1줄로만 작성**합니다.
|
||||||
|
- 컨트롤러 클래스는 `@Controller` 대신 **`@RestController`**를 사용하며, `@ResponseBody`는 생략합니다.
|
||||||
|
- 데이터 입출력 메소드의 파라미터는 **단일 DTO 하나만 `@RequestBody`**로 받습니다.
|
||||||
|
- 파일 업로드가 포함된 경우에만 `@ModelAttribute` + `@RequestParam MultipartFile`을 허용합니다.
|
||||||
|
- 화면 이동(`move~`) 메소드는 **`ModelAndView`를 리턴**합니다. (`@RestController`에서 String 리턴 시 뷰 이름이 아닌 응답 바디로 해석되므로)
|
||||||
|
- 화면 이동 메소드의 뷰 경로는 **컨트롤러에서 직접 명시**합니다. (서비스에 위임 금지)
|
||||||
|
|
||||||
|
### 5-2. 서비스 원칙 (Service Layer)
|
||||||
|
- 에러 처리(try-catch), 응답 메시지(msgCode, msgDesc) 설정은 **서비스 계층에서 전담**합니다.
|
||||||
|
- `HttpServletRequest`, `HttpSession`은 `@Autowired`로 직접 주입받아 사용합니다. (Spring이 Request-scope 프록시로 제공)
|
||||||
|
- `session.getAttribute("loginMemberId")`를 통해 로그인 ID를 가져오고, DTO에 설정합니다.
|
||||||
|
|
||||||
|
### 5-3. DTO 원칙 (DTO Communication)
|
||||||
|
- **HashMap 사용 금지**. 컨트롤러 ↔ 서비스 ↔ 매퍼 간 모든 데이터는 **DTO 객체만 사용**합니다.
|
||||||
|
- DTO에는 `@Data` (Lombok)을 사용합니다.
|
||||||
|
- DTO 필드 구성:
|
||||||
|
- **DB 컬럼 매핑 필드**: `muProcedureReviewId`, `title`, `content` 등
|
||||||
|
- **조회 결과 전용 필드**: `rowNum`, `writeDate`, `writeName` 등
|
||||||
|
- **검색/UI 변수**: `startDate`, `endDate`, `start`, `limit`, `sort`, `dir` 등
|
||||||
|
- **응답 매핑 변수**: `msgCode`, `msgDesc`, `success`, `totalCount`, `rows`(Object 타입), `tId`
|
||||||
|
|
||||||
|
### 5-4. Mapper 원칙 (MyBatis Mapper)
|
||||||
|
- Mapper는 **`@Mapper` 어노테이션을 사용한 인터페이스**로 작성합니다. (`SqlSessionDaoSupport` 상속 금지)
|
||||||
|
- XML Mapper의 `namespace`는 Mapper 인터페이스의 **FQCN(Fully Qualified Class Name)**과 일치시킵니다.
|
||||||
|
- XML의 `resultType`은 `hashmap` 대신 **DTO FQCN**을 사용합니다.
|
||||||
|
- 예외: 도메인 외부 테이블 조회(카테고리 등)는 `hashmap` 허용
|
||||||
|
- XML alias는 **DTO 필드명(camelCase)**과 정확히 일치시킵니다.
|
||||||
|
- 단건 조회는 `List` 대신 **DTO 단일 객체를 리턴**합니다.
|
||||||
|
|
||||||
|
## 6. 파일 업로드 규칙 (File Upload)
|
||||||
|
- `MultipartFile.transferTo()` 사용 시 반드시 **절대경로를 명시**합니다:
|
||||||
|
```java
|
||||||
|
File dest = new File(outDir, savedName);
|
||||||
|
file.transferTo(dest.toPath().toAbsolutePath());
|
||||||
|
```
|
||||||
|
- 상대경로 사용 시 Tomcat 임시 디렉토리 기준으로 해석되어 오류가 발생합니다.
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
package com.madeuhome.common.ctrl;
|
package com.madeuhome.common.ctrl;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
@@ -24,12 +23,13 @@ public class MenuController {
|
|||||||
String requestURI = request.getRequestURI();
|
String requestURI = request.getRequestURI();
|
||||||
|
|
||||||
// 특정 URL 패턴에만 메뉴 추가
|
// 특정 URL 패턴에만 메뉴 추가
|
||||||
if (requestURI.endsWith("Intro.do") || requestURI.startsWith("/index") ) {
|
/*
|
||||||
|
* if (requestURI.endsWith("Intro.do") || requestURI.startsWith("/index") ) {
|
||||||
|
* return menuService.getMenuHierarchy("MAIN"); }
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
return menuService.getMenuHierarchy("MAIN");
|
return menuService.getMenuHierarchy("MAIN");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return new ArrayList<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,209 @@
|
|||||||
|
package com.madeuhome.controller.web.reservation;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Controller;
|
||||||
|
import org.springframework.ui.Model;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.servlet.ModelAndView;
|
||||||
|
|
||||||
|
import com.madeuhome.constants.Constants;
|
||||||
|
import com.madeuhome.service.web.reservation.ReservationService;
|
||||||
|
import com.madeuhome.util.HttpUtil;
|
||||||
|
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import jakarta.servlet.http.HttpSession;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 예약 컨트롤러
|
||||||
|
*/
|
||||||
|
@Controller
|
||||||
|
@Slf4j
|
||||||
|
public class ReservationController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ReservationService reservationService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 예약 페이지 이동
|
||||||
|
*/
|
||||||
|
@RequestMapping(value = "/webservice/selectMakeReservation.do")
|
||||||
|
public String selectMakeReservation(HttpSession session, HttpServletRequest request, Model model) {
|
||||||
|
log.debug("ReservationController selectMakeReservation START");
|
||||||
|
HashMap<String, Object> paramMap = HttpUtil.getParameterMap(request);
|
||||||
|
model.addAttribute("CATEGORY_DIV_CD", paramMap.get("CATEGORY_DIV_CD"));
|
||||||
|
model.addAttribute("CATEGORY_NO", paramMap.get("CATEGORY_NO"));
|
||||||
|
model.addAttribute("POST_NO", paramMap.get("POST_NO"));
|
||||||
|
model.addAttribute("PROCEDURE_ID", paramMap.get("PROCEDURE_ID"));
|
||||||
|
log.debug("ReservationController selectMakeReservation END");
|
||||||
|
return "/web/service/makeReservation";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 예약 시술 정보 조회
|
||||||
|
*/
|
||||||
|
@RequestMapping(value = "/webservice/selectReservation.do")
|
||||||
|
public ModelAndView selectReservation(HttpSession session, HttpServletRequest request,
|
||||||
|
HttpServletResponse response) {
|
||||||
|
log.debug("ReservationController selectReservation START");
|
||||||
|
|
||||||
|
HashMap<String, Object> paramMap = HttpUtil.getParameterMap(request);
|
||||||
|
HashMap<String, Object> map = new HashMap<>();
|
||||||
|
StringBuffer errorMsg = new StringBuffer();
|
||||||
|
|
||||||
|
try {
|
||||||
|
map = reservationService.selectReservation(paramMap);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
errorMsg.append(e);
|
||||||
|
return null;
|
||||||
|
} finally {
|
||||||
|
if (Constants.OK == map.get("msgCode")) {
|
||||||
|
} else {
|
||||||
|
if (null == map.get("msgCode") || ("").equals(map.get("msgCode"))) {
|
||||||
|
map.put("msgCode", Constants.FAIL);
|
||||||
|
}
|
||||||
|
map.put("success", false);
|
||||||
|
if (null == map.get("msgDesc") || ("").equals(map.get("msgDesc"))) {
|
||||||
|
map.put("msgDesc", "정상적으로 수행되지 않았습니다. 관리자에게 문의하시기 바랍니다.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.debug("ReservationController selectReservation END");
|
||||||
|
return HttpUtil.makeHashToJsonModelAndView(map);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 병원 휴일 조회 (달력 표출용)
|
||||||
|
*/
|
||||||
|
@RequestMapping(value = "/webservice/selectHospitalHolidayList.do")
|
||||||
|
public ModelAndView selectHospitalHolidayList(HttpSession session, HttpServletRequest request,
|
||||||
|
HttpServletResponse response) {
|
||||||
|
log.debug("ReservationController selectHospitalHolidayList START");
|
||||||
|
|
||||||
|
HashMap<String, Object> paramMap = HttpUtil.getParameterMap(request);
|
||||||
|
HashMap<String, Object> map = new HashMap<>();
|
||||||
|
|
||||||
|
try {
|
||||||
|
map = reservationService.selectHospitalHolidayList(paramMap);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return null;
|
||||||
|
} finally {
|
||||||
|
if (Constants.OK != map.get("msgCode")) {
|
||||||
|
map.put("msgCode", Constants.FAIL);
|
||||||
|
map.put("success", false);
|
||||||
|
if (null == map.get("msgDesc") || ("").equals(map.get("msgDesc"))) {
|
||||||
|
map.put("msgDesc", "정상적으로 수행되지 않았습니다. 관리자에게 문의하시기 바랍니다.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.debug("ReservationController selectHospitalHolidayList END");
|
||||||
|
return HttpUtil.makeHashToJsonModelAndView(map);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 특정 날짜 운영시간 조회
|
||||||
|
*/
|
||||||
|
@RequestMapping(value = "/webservice/selectHospitalWorkTime.do")
|
||||||
|
public ModelAndView selectHospitalWorkTime(HttpSession session, HttpServletRequest request,
|
||||||
|
HttpServletResponse response) {
|
||||||
|
log.debug("ReservationController selectHospitalWorkTime START");
|
||||||
|
|
||||||
|
HashMap<String, Object> paramMap = HttpUtil.getParameterMap(request);
|
||||||
|
HashMap<String, Object> map = new HashMap<>();
|
||||||
|
|
||||||
|
try {
|
||||||
|
map = reservationService.selectHospitalWorkTime(paramMap);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return null;
|
||||||
|
} finally {
|
||||||
|
if (Constants.OK != map.get("msgCode")) {
|
||||||
|
map.put("msgCode", Constants.FAIL);
|
||||||
|
map.put("success", false);
|
||||||
|
if (null == map.get("msgDesc") || ("").equals(map.get("msgDesc"))) {
|
||||||
|
map.put("msgDesc", "정상적으로 수행되지 않았습니다. 관리자에게 문의하시기 바랍니다.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.debug("ReservationController selectHospitalWorkTime END");
|
||||||
|
return HttpUtil.makeHashToJsonModelAndView(map);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 예약 카운트 조회
|
||||||
|
*/
|
||||||
|
@RequestMapping(value = "/webservice/selectReservationCnt.do")
|
||||||
|
public ModelAndView selectReservationCnt(HttpSession session, HttpServletRequest request,
|
||||||
|
HttpServletResponse response) {
|
||||||
|
log.debug("ReservationController selectReservationCnt START");
|
||||||
|
|
||||||
|
HashMap<String, Object> paramMap = HttpUtil.getParameterMap(request);
|
||||||
|
HashMap<String, Object> map = new HashMap<>();
|
||||||
|
StringBuffer errorMsg = new StringBuffer();
|
||||||
|
|
||||||
|
try {
|
||||||
|
map = reservationService.selectReservationCnt(paramMap);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
errorMsg.append(e);
|
||||||
|
return null;
|
||||||
|
} finally {
|
||||||
|
if (Constants.OK == map.get("msgCode")) {
|
||||||
|
} else {
|
||||||
|
if (null == map.get("msgCode") || ("").equals(map.get("msgCode"))) {
|
||||||
|
map.put("msgCode", Constants.FAIL);
|
||||||
|
}
|
||||||
|
map.put("success", false);
|
||||||
|
if (null == map.get("msgDesc") || ("").equals(map.get("msgDesc"))) {
|
||||||
|
map.put("msgDesc", "정상적으로 수행되지 않았습니다. 관리자에게 문의하시기 바랍니다.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.debug("ReservationController selectReservationCnt END");
|
||||||
|
return HttpUtil.makeHashToJsonModelAndView(map);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 예약 저장
|
||||||
|
*/
|
||||||
|
@RequestMapping(value = "/webservice/insertReservation.do")
|
||||||
|
public ModelAndView insertReservation(HttpSession session, HttpServletRequest request,
|
||||||
|
HttpServletResponse response) {
|
||||||
|
log.debug("ReservationController insertReservation START");
|
||||||
|
|
||||||
|
HashMap<String, Object> paramMap = HttpUtil.getParameterMap(request);
|
||||||
|
HashMap<String, Object> map = new HashMap<>();
|
||||||
|
StringBuffer errorMsg = new StringBuffer();
|
||||||
|
|
||||||
|
try {
|
||||||
|
map = reservationService.insertReservation(paramMap);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
errorMsg.append(e);
|
||||||
|
return null;
|
||||||
|
} finally {
|
||||||
|
if (Constants.OK == map.get("msgCode")) {
|
||||||
|
} else {
|
||||||
|
if (null == map.get("msgCode") || ("").equals(map.get("msgCode"))) {
|
||||||
|
map.put("msgCode", Constants.FAIL);
|
||||||
|
}
|
||||||
|
map.put("success", false);
|
||||||
|
if (null == map.get("msgDesc") || ("").equals(map.get("msgDesc"))) {
|
||||||
|
map.put("msgDesc", "정상적으로 수행되지 않았습니다. 관리자에게 문의하시기 바랍니다.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.debug("ReservationController insertReservation END");
|
||||||
|
return HttpUtil.makeHashToJsonModelAndView(map);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,7 +18,6 @@ import org.springframework.web.servlet.ModelAndView;
|
|||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Controller
|
@Controller
|
||||||
public class WebEventController extends ManagerDraftAction {
|
public class WebEventController extends ManagerDraftAction {
|
||||||
@@ -53,7 +52,8 @@ public class WebEventController extends ManagerDraftAction{
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@RequestMapping(value = "/webevent/selectListWebEvent.do")
|
@RequestMapping(value = "/webevent/selectListWebEvent.do")
|
||||||
public ModelAndView selectListWebEvent(HttpSession session,HttpServletRequest request, HttpServletResponse response) {
|
public ModelAndView selectListWebEvent(HttpSession session, HttpServletRequest request,
|
||||||
|
HttpServletResponse response) {
|
||||||
|
|
||||||
log.debug("WebEventController selectListWebEvent START");
|
log.debug("WebEventController selectListWebEvent START");
|
||||||
|
|
||||||
@@ -111,7 +111,6 @@ public class WebEventController extends ManagerDraftAction{
|
|||||||
|
|
||||||
log.debug("WebEventController selectListWebEvent END");
|
log.debug("WebEventController selectListWebEvent END");
|
||||||
|
|
||||||
|
|
||||||
return HttpUtil.makeHashToJsonModelAndView(map);
|
return HttpUtil.makeHashToJsonModelAndView(map);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -180,7 +179,6 @@ public class WebEventController extends ManagerDraftAction{
|
|||||||
|
|
||||||
log.debug("WebEventController selectListEvent END");
|
log.debug("WebEventController selectListEvent END");
|
||||||
|
|
||||||
|
|
||||||
return HttpUtil.makeHashToJsonModelAndView(map);
|
return HttpUtil.makeHashToJsonModelAndView(map);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -212,7 +210,8 @@ public class WebEventController extends ManagerDraftAction{
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@RequestMapping(value = "/webevent/selectEventDetail.do")
|
@RequestMapping(value = "/webevent/selectEventDetail.do")
|
||||||
public ModelAndView selectEventDetail(HttpSession session, HttpServletRequest request, HttpServletResponse response) {
|
public ModelAndView selectEventDetail(HttpSession session, HttpServletRequest request,
|
||||||
|
HttpServletResponse response) {
|
||||||
|
|
||||||
log.debug("WebEventController selectEventDetail START");
|
log.debug("WebEventController selectEventDetail START");
|
||||||
|
|
||||||
@@ -269,7 +268,6 @@ public class WebEventController extends ManagerDraftAction{
|
|||||||
|
|
||||||
log.debug("WebEventController selectEventDetail END");
|
log.debug("WebEventController selectEventDetail END");
|
||||||
|
|
||||||
|
|
||||||
return HttpUtil.makeHashToJsonModelAndView(map);
|
return HttpUtil.makeHashToJsonModelAndView(map);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -282,214 +280,11 @@ public class WebEventController extends ManagerDraftAction{
|
|||||||
model.addAttribute("CATEGORY_NO", paramMap.get("CATEGORY_NO"));
|
model.addAttribute("CATEGORY_NO", paramMap.get("CATEGORY_NO"));
|
||||||
model.addAttribute("POST_NO", paramMap.get("POST_NO"));
|
model.addAttribute("POST_NO", paramMap.get("POST_NO"));
|
||||||
model.addAttribute("PROCEDURE_ID", paramMap.get("PROCEDURE_ID"));
|
model.addAttribute("PROCEDURE_ID", paramMap.get("PROCEDURE_ID"));
|
||||||
|
model.addAttribute("EVENT_START_DT", paramMap.get("EVENT_START_DT"));
|
||||||
|
model.addAttribute("EVENT_END_DT", paramMap.get("EVENT_END_DT"));
|
||||||
|
|
||||||
log.debug("WebServiceController selectMakeReservation END");
|
log.debug("WebServiceController selectMakeReservation END");
|
||||||
|
|
||||||
return "/web/webevent/makeReservation";
|
return "/web/service/makeReservation";
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 시술 목록 상세 조회
|
|
||||||
*
|
|
||||||
* @param request
|
|
||||||
* @param response
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
@RequestMapping(value="/webevent/selectReservation.do")
|
|
||||||
public ModelAndView selectReservation(HttpSession session, HttpServletRequest request, HttpServletResponse response) {
|
|
||||||
|
|
||||||
log.debug("WebServiceController selectReservation START");
|
|
||||||
|
|
||||||
HashMap<String, Object> paramMap = HttpUtil.getParameterMap(request);
|
|
||||||
HashMap<String, Object> map = new HashMap<String, Object>();
|
|
||||||
StringBuffer errorMsg = new StringBuffer();
|
|
||||||
|
|
||||||
try{
|
|
||||||
map = webEventService.selectReservation(paramMap);
|
|
||||||
}catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
errorMsg.append(e);
|
|
||||||
return null;
|
|
||||||
}finally {
|
|
||||||
if(Constants.OK == map.get("msgCode")) {
|
|
||||||
|
|
||||||
}else{
|
|
||||||
if(null == map.get("msgCode") || ("").equals(map.get("msgCode"))) {
|
|
||||||
map.put("msgCode", Constants.FAIL);
|
|
||||||
}
|
|
||||||
|
|
||||||
map.put("success", false);
|
|
||||||
if(null == map.get("msgDesc") || ("").equals(map.get("msgDesc"))) {
|
|
||||||
map.put("msgDesc","정상적으로 수행되지 않았습니다. 관리자에게 문의하시기 바랍니다. (E0029)");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
HashMap<String, Object> visitLogParamMap = RequestLogUtil.getVisitLogParameterMap(request);
|
|
||||||
HashMap<String, Object> insertMap = new HashMap<String, Object>();
|
|
||||||
|
|
||||||
insertMap.put("url", "/webevent/selectReservation.do");
|
|
||||||
insertMap.put("func", "selectListService");
|
|
||||||
insertMap.put("funcName", "예약 조회");
|
|
||||||
insertMap.put("service", "webEventService");
|
|
||||||
insertMap.put("serviceName", "예약 상세");
|
|
||||||
insertMap.put("requestValue", String.valueOf(paramMap));
|
|
||||||
insertMap.put("responseValue", String.valueOf(map));
|
|
||||||
;
|
|
||||||
if(("true").equals(String.valueOf(map.get("success")))){
|
|
||||||
insertMap.put("resultCode", "SUCCESS");
|
|
||||||
}else{
|
|
||||||
insertMap.put("resultCode", "ERROR");
|
|
||||||
}
|
|
||||||
|
|
||||||
insertMap.put("resultMsg", String.valueOf(errorMsg));
|
|
||||||
|
|
||||||
// logHistoryService.insertLogHistory(insertMap, visitLogParamMap);
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
log.debug("WebServiceController selectReservation END");
|
|
||||||
|
|
||||||
|
|
||||||
return HttpUtil.makeHashToJsonModelAndView(map);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 시술 목록 상세 조회
|
|
||||||
*
|
|
||||||
* @param request
|
|
||||||
* @param response
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
@RequestMapping(value="/webevent/selectReservationCnt.do")
|
|
||||||
public ModelAndView selectReservationCnt(HttpSession session, HttpServletRequest request, HttpServletResponse response) {
|
|
||||||
|
|
||||||
log.debug("WebServiceController selectReservationCnt START");
|
|
||||||
|
|
||||||
HashMap<String, Object> paramMap = HttpUtil.getParameterMap(request);
|
|
||||||
HashMap<String, Object> map = new HashMap<String, Object>();
|
|
||||||
StringBuffer errorMsg = new StringBuffer();
|
|
||||||
|
|
||||||
try{
|
|
||||||
map = webEventService.selectReservationCnt(paramMap);
|
|
||||||
}catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
errorMsg.append(e);
|
|
||||||
return null;
|
|
||||||
}finally {
|
|
||||||
if(Constants.OK == map.get("msgCode")) {
|
|
||||||
|
|
||||||
}else{
|
|
||||||
if(null == map.get("msgCode") || ("").equals(map.get("msgCode"))) {
|
|
||||||
map.put("msgCode", Constants.FAIL);
|
|
||||||
}
|
|
||||||
|
|
||||||
map.put("success", false);
|
|
||||||
if(null == map.get("msgDesc") || ("").equals(map.get("msgDesc"))) {
|
|
||||||
map.put("msgDesc","정상적으로 수행되지 않았습니다. 관리자에게 문의하시기 바랍니다. (E0029)");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
HashMap<String, Object> visitLogParamMap = RequestLogUtil.getVisitLogParameterMap(request);
|
|
||||||
HashMap<String, Object> insertMap = new HashMap<String, Object>();
|
|
||||||
|
|
||||||
insertMap.put("url", "/webevent/selectReservationCnt.do");
|
|
||||||
insertMap.put("func", "selectReservationCnt");
|
|
||||||
insertMap.put("funcName", "예약 조회");
|
|
||||||
insertMap.put("service", "webEventService");
|
|
||||||
insertMap.put("serviceName", "예약 상세");
|
|
||||||
insertMap.put("requestValue", String.valueOf(paramMap));
|
|
||||||
insertMap.put("responseValue", String.valueOf(map));
|
|
||||||
;
|
|
||||||
if(("true").equals(String.valueOf(map.get("success")))){
|
|
||||||
insertMap.put("resultCode", "SUCCESS");
|
|
||||||
}else{
|
|
||||||
insertMap.put("resultCode", "ERROR");
|
|
||||||
}
|
|
||||||
|
|
||||||
insertMap.put("resultMsg", String.valueOf(errorMsg));
|
|
||||||
|
|
||||||
// logHistoryService.insertLogHistory(insertMap, visitLogParamMap);
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
log.debug("WebServiceController selectReservationCnt END");
|
|
||||||
|
|
||||||
|
|
||||||
return HttpUtil.makeHashToJsonModelAndView(map);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 예약 저장
|
|
||||||
*
|
|
||||||
* @param request
|
|
||||||
* @param response
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
@RequestMapping(value="/webevent/insertReservation.do")
|
|
||||||
public ModelAndView insertReservation(HttpSession session, HttpServletRequest request, HttpServletResponse response) {
|
|
||||||
|
|
||||||
log.debug("WebServiceController insertReservation START");
|
|
||||||
|
|
||||||
HashMap<String, Object> paramMap = HttpUtil.getParameterMap(request);
|
|
||||||
HashMap<String, Object> map = new HashMap<String, Object>();
|
|
||||||
StringBuffer errorMsg = new StringBuffer();
|
|
||||||
|
|
||||||
try{
|
|
||||||
map = webEventService.insertReservation(paramMap);
|
|
||||||
log.debug(map + "TEST");
|
|
||||||
}catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
errorMsg.append(e);
|
|
||||||
return null;
|
|
||||||
}finally {
|
|
||||||
if(Constants.OK == map.get("msgCode")) {
|
|
||||||
|
|
||||||
}else{
|
|
||||||
if(null == map.get("msgCode") || ("").equals(map.get("msgCode"))) {
|
|
||||||
map.put("msgCode", Constants.FAIL);
|
|
||||||
}
|
|
||||||
|
|
||||||
map.put("success", false);
|
|
||||||
if(null == map.get("msgDesc") || ("").equals(map.get("msgDesc"))) {
|
|
||||||
map.put("msgDesc","정상적으로 수행되지 않았습니다. 관리자에게 문의하시기 바랍니다. (E0029)");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
HashMap<String, Object> visitLogParamMap = RequestLogUtil.getVisitLogParameterMap(request);
|
|
||||||
HashMap<String, Object> insertMap = new HashMap<String, Object>();
|
|
||||||
|
|
||||||
insertMap.put("url", "/webevent/insertReservation.do");
|
|
||||||
insertMap.put("func", "selectReservationCnt");
|
|
||||||
insertMap.put("funcName", "예약 저장");
|
|
||||||
insertMap.put("service", "webEventService");
|
|
||||||
insertMap.put("serviceName", "예약 저장");
|
|
||||||
insertMap.put("requestValue", String.valueOf(paramMap));
|
|
||||||
insertMap.put("responseValue", String.valueOf(map));
|
|
||||||
;
|
|
||||||
if(("true").equals(String.valueOf(map.get("success")))){
|
|
||||||
insertMap.put("resultCode", "SUCCESS");
|
|
||||||
}else{
|
|
||||||
insertMap.put("resultCode", "ERROR");
|
|
||||||
}
|
|
||||||
|
|
||||||
insertMap.put("resultMsg", String.valueOf(errorMsg));
|
|
||||||
|
|
||||||
// logHistoryService.insertLogHistory(insertMap, visitLogParamMap);
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
log.debug("WebServiceController insertReservation END");
|
|
||||||
|
|
||||||
|
|
||||||
return HttpUtil.makeHashToJsonModelAndView(map);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import jakarta.servlet.http.HttpServletRequest;
|
|||||||
import jakarta.servlet.http.HttpSession;
|
import jakarta.servlet.http.HttpSession;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@@ -19,16 +19,16 @@ public class WebHomeController extends ManagerDraftAction{
|
|||||||
* @param response
|
* @param response
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@RequestMapping(value="/")
|
@GetMapping("/")
|
||||||
public String homeIntro(HttpSession session,HttpServletRequest request) {
|
public String homeIntro(HttpSession session,HttpServletRequest request) {
|
||||||
|
|
||||||
log.debug("WebHomeController homeIntro START");
|
log.debug("WebHomeController homeIntro START");
|
||||||
|
|
||||||
log.debug("WebHomeController homeIntro END");
|
log.debug("WebHomeController homeIntro END");
|
||||||
return "/intro";
|
return "/index";
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequestMapping(value="/index")
|
@GetMapping("/index")
|
||||||
public String homeIndex(HttpSession session,HttpServletRequest request) {
|
public String homeIndex(HttpSession session,HttpServletRequest request) {
|
||||||
|
|
||||||
log.debug("WebHomeController homeIndex START");
|
log.debug("WebHomeController homeIndex START");
|
||||||
|
|||||||
@@ -0,0 +1,95 @@
|
|||||||
|
package com.madeuhome.controller.web.webreview;
|
||||||
|
|
||||||
|
import com.madeuhome.constants.Constants;
|
||||||
|
import com.madeuhome.init.ManagerDraftAction;
|
||||||
|
import com.madeuhome.service.web.webreview.WebReviewService;
|
||||||
|
import com.madeuhome.util.HttpUtil;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import jakarta.servlet.http.HttpSession;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Controller;
|
||||||
|
import org.springframework.ui.Model;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.servlet.ModelAndView;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Controller
|
||||||
|
public class WebReviewController extends ManagerDraftAction {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private WebReviewService webReviewService;
|
||||||
|
|
||||||
|
@RequestMapping(value = "/webreview/selectListProcedureReviewIntro.do")
|
||||||
|
public String selectListProcedureReviewIntro(HttpSession session, HttpServletRequest request) {
|
||||||
|
log.debug("WebReviewController selectListProcedureReviewIntro START");
|
||||||
|
log.debug("WebReviewController selectListProcedureReviewIntro END");
|
||||||
|
return "/web/webreview/procedureReviewSelectList";
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequestMapping(value = "/webreview/selectListProcedureReview.do")
|
||||||
|
public ModelAndView selectListProcedureReview(HttpSession session, HttpServletRequest request,
|
||||||
|
HttpServletResponse response) {
|
||||||
|
log.debug("WebReviewController selectListProcedureReview START");
|
||||||
|
HashMap<String, Object> paramMap = HttpUtil.getParameterMap(request);
|
||||||
|
HashMap<String, Object> map = new HashMap<String, Object>();
|
||||||
|
try {
|
||||||
|
map = webReviewService.selectListProcedureReview(paramMap);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return null;
|
||||||
|
} finally {
|
||||||
|
if (Constants.OK == map.get("msgCode")) {
|
||||||
|
} else {
|
||||||
|
if (null == map.get("msgCode") || ("").equals(map.get("msgCode"))) {
|
||||||
|
map.put("msgCode", Constants.FAIL);
|
||||||
|
}
|
||||||
|
map.put("success", false);
|
||||||
|
if (null == map.get("msgDesc") || ("").equals(map.get("msgDesc"))) {
|
||||||
|
map.put("msgDesc", "정상적으로 수행되지 않았습니다.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.debug("WebReviewController selectListProcedureReview END");
|
||||||
|
return HttpUtil.makeHashToJsonModelAndView(map);
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequestMapping(value = "/webreview/selectProcedureReviewIntro.do")
|
||||||
|
public String selectProcedureReviewIntro(HttpSession session, HttpServletRequest request, Model model) {
|
||||||
|
log.debug("WebReviewController selectProcedureReviewIntro START");
|
||||||
|
HashMap<String, Object> paramMap = HttpUtil.getParameterMap(request);
|
||||||
|
model.addAttribute("muProcedureReviewId", paramMap.get("muProcedureReviewId"));
|
||||||
|
log.debug("WebReviewController selectProcedureReviewIntro END");
|
||||||
|
return "/web/webreview/procedureReviewSelect";
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequestMapping(value = "/webreview/selectProcedureReview.do")
|
||||||
|
public ModelAndView selectProcedureReview(HttpSession session, HttpServletRequest request,
|
||||||
|
HttpServletResponse response) {
|
||||||
|
log.debug("WebReviewController selectProcedureReview START");
|
||||||
|
HashMap<String, Object> paramMap = HttpUtil.getParameterMap(request);
|
||||||
|
HashMap<String, Object> map = new HashMap<String, Object>();
|
||||||
|
try {
|
||||||
|
map = webReviewService.selectProcedureReview(paramMap);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return null;
|
||||||
|
} finally {
|
||||||
|
if (Constants.OK == map.get("msgCode")) {
|
||||||
|
} else {
|
||||||
|
if (null == map.get("msgCode") || ("").equals(map.get("msgCode"))) {
|
||||||
|
map.put("msgCode", Constants.FAIL);
|
||||||
|
}
|
||||||
|
map.put("success", false);
|
||||||
|
if (null == map.get("msgDesc") || ("").equals(map.get("msgDesc"))) {
|
||||||
|
map.put("msgDesc", "정상적으로 수행되지 않았습니다.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.debug("WebReviewController selectProcedureReview END");
|
||||||
|
return HttpUtil.makeHashToJsonModelAndView(map);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -25,7 +25,6 @@ import jakarta.servlet.http.HttpServletResponse;
|
|||||||
import jakarta.servlet.http.HttpSession;
|
import jakarta.servlet.http.HttpSession;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Controller
|
@Controller
|
||||||
public class WebServiceController extends ManagerDraftAction {
|
public class WebServiceController extends ManagerDraftAction {
|
||||||
@@ -57,7 +56,8 @@ public class WebServiceController extends ManagerDraftAction{
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@RequestMapping(value = "/webservice/selectListCategory.do")
|
@RequestMapping(value = "/webservice/selectListCategory.do")
|
||||||
public ModelAndView selectListCategory(HttpSession session,HttpServletRequest request, HttpServletResponse response) {
|
public ModelAndView selectListCategory(HttpSession session, HttpServletRequest request,
|
||||||
|
HttpServletResponse response) {
|
||||||
|
|
||||||
log.debug("WebServiceController selectListCategory START");
|
log.debug("WebServiceController selectListCategory START");
|
||||||
|
|
||||||
@@ -115,7 +115,6 @@ public class WebServiceController extends ManagerDraftAction{
|
|||||||
|
|
||||||
log.debug("WebServiceController selectListCategory END");
|
log.debug("WebServiceController selectListCategory END");
|
||||||
|
|
||||||
|
|
||||||
return HttpUtil.makeHashToJsonModelAndView(map);
|
return HttpUtil.makeHashToJsonModelAndView(map);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -176,7 +175,8 @@ public class WebServiceController extends ManagerDraftAction{
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@RequestMapping(value = "/webservice/selectServiceDetail.do")
|
@RequestMapping(value = "/webservice/selectServiceDetail.do")
|
||||||
public ModelAndView selectServiceDetail(HttpSession session, HttpServletRequest request, HttpServletResponse response) {
|
public ModelAndView selectServiceDetail(HttpSession session, HttpServletRequest request,
|
||||||
|
HttpServletResponse response) {
|
||||||
|
|
||||||
log.debug("WebServiceController selectServiceDetail START");
|
log.debug("WebServiceController selectServiceDetail START");
|
||||||
|
|
||||||
@@ -232,227 +232,6 @@ public class WebServiceController extends ManagerDraftAction{
|
|||||||
|
|
||||||
log.debug("WebServiceController selectServiceDetail END");
|
log.debug("WebServiceController selectServiceDetail END");
|
||||||
|
|
||||||
|
|
||||||
return HttpUtil.makeHashToJsonModelAndView(map);
|
|
||||||
}
|
|
||||||
|
|
||||||
@RequestMapping(value="/webservice/selectMakeReservation.do")
|
|
||||||
public String selectMakeReservation(HttpSession session, HttpServletRequest request, Model model) {
|
|
||||||
|
|
||||||
log.debug("WebServiceController selectMakeReservation START");
|
|
||||||
HashMap<String, Object> paramMap = HttpUtil.getParameterMap(request);
|
|
||||||
model.addAttribute("CATEGORY_DIV_CD", paramMap.get("CATEGORY_DIV_CD"));
|
|
||||||
model.addAttribute("CATEGORY_NO", paramMap.get("CATEGORY_NO"));
|
|
||||||
model.addAttribute("POST_NO", paramMap.get("POST_NO"));
|
|
||||||
model.addAttribute("PROCEDURE_ID", paramMap.get("PROCEDURE_ID"));
|
|
||||||
|
|
||||||
log.debug("WebServiceController selectMakeReservation END");
|
|
||||||
|
|
||||||
return "/web/service/makeReservation";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 시술 목록 상세 조회
|
|
||||||
*
|
|
||||||
* @param request
|
|
||||||
* @param response
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
@RequestMapping(value="/webservice/selectReservation.do")
|
|
||||||
public ModelAndView selectReservation(HttpSession session, HttpServletRequest request, HttpServletResponse response) {
|
|
||||||
|
|
||||||
log.debug("WebServiceController selectReservation START");
|
|
||||||
|
|
||||||
HashMap<String, Object> paramMap = HttpUtil.getParameterMap(request);
|
|
||||||
HashMap<String, Object> map = new HashMap<String, Object>();
|
|
||||||
StringBuffer errorMsg = new StringBuffer();
|
|
||||||
|
|
||||||
try{
|
|
||||||
map = webServiceService.selectReservation(paramMap);
|
|
||||||
}catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
errorMsg.append(e);
|
|
||||||
return null;
|
|
||||||
}finally {
|
|
||||||
if(Constants.OK == map.get("msgCode")) {
|
|
||||||
|
|
||||||
}else{
|
|
||||||
if(null == map.get("msgCode") || ("").equals(map.get("msgCode"))) {
|
|
||||||
map.put("msgCode", Constants.FAIL);
|
|
||||||
}
|
|
||||||
|
|
||||||
map.put("success", false);
|
|
||||||
if(null == map.get("msgDesc") || ("").equals(map.get("msgDesc"))) {
|
|
||||||
map.put("msgDesc","정상적으로 수행되지 않았습니다. 관리자에게 문의하시기 바랍니다. (E0029)");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
HashMap<String, Object> visitLogParamMap = RequestLogUtil.getVisitLogParameterMap(request);
|
|
||||||
HashMap<String, Object> insertMap = new HashMap<String, Object>();
|
|
||||||
|
|
||||||
insertMap.put("url", "/webservice/selectReservation.do");
|
|
||||||
insertMap.put("func", "selectListService");
|
|
||||||
insertMap.put("funcName", "예약 조회");
|
|
||||||
insertMap.put("service", "webServiceService");
|
|
||||||
insertMap.put("serviceName", "예약 상세");
|
|
||||||
insertMap.put("requestValue", String.valueOf(paramMap));
|
|
||||||
insertMap.put("responseValue", String.valueOf(map));
|
|
||||||
;
|
|
||||||
if(("true").equals(String.valueOf(map.get("success")))){
|
|
||||||
insertMap.put("resultCode", "SUCCESS");
|
|
||||||
}else{
|
|
||||||
insertMap.put("resultCode", "ERROR");
|
|
||||||
}
|
|
||||||
|
|
||||||
insertMap.put("resultMsg", String.valueOf(errorMsg));
|
|
||||||
|
|
||||||
// logHistoryService.insertLogHistory(insertMap, visitLogParamMap);
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
log.debug("WebServiceController selectReservation END");
|
|
||||||
|
|
||||||
|
|
||||||
return HttpUtil.makeHashToJsonModelAndView(map);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 시술 목록 상세 조회
|
|
||||||
*
|
|
||||||
* @param request
|
|
||||||
* @param response
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
@RequestMapping(value="/webservice/selectReservationCnt.do")
|
|
||||||
public ModelAndView selectReservationCnt(HttpSession session, HttpServletRequest request, HttpServletResponse response) {
|
|
||||||
|
|
||||||
log.debug("WebServiceController selectReservationCnt START");
|
|
||||||
|
|
||||||
HashMap<String, Object> paramMap = HttpUtil.getParameterMap(request);
|
|
||||||
HashMap<String, Object> map = new HashMap<String, Object>();
|
|
||||||
StringBuffer errorMsg = new StringBuffer();
|
|
||||||
|
|
||||||
try{
|
|
||||||
map = webServiceService.selectReservationCnt(paramMap);
|
|
||||||
}catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
errorMsg.append(e);
|
|
||||||
return null;
|
|
||||||
}finally {
|
|
||||||
if(Constants.OK == map.get("msgCode")) {
|
|
||||||
|
|
||||||
}else{
|
|
||||||
if(null == map.get("msgCode") || ("").equals(map.get("msgCode"))) {
|
|
||||||
map.put("msgCode", Constants.FAIL);
|
|
||||||
}
|
|
||||||
|
|
||||||
map.put("success", false);
|
|
||||||
if(null == map.get("msgDesc") || ("").equals(map.get("msgDesc"))) {
|
|
||||||
map.put("msgDesc","정상적으로 수행되지 않았습니다. 관리자에게 문의하시기 바랍니다. (E0029)");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
HashMap<String, Object> visitLogParamMap = RequestLogUtil.getVisitLogParameterMap(request);
|
|
||||||
HashMap<String, Object> insertMap = new HashMap<String, Object>();
|
|
||||||
|
|
||||||
insertMap.put("url", "/webservice/selectReservationCnt.do");
|
|
||||||
insertMap.put("func", "selectReservationCnt");
|
|
||||||
insertMap.put("funcName", "예약 조회");
|
|
||||||
insertMap.put("service", "webServiceService");
|
|
||||||
insertMap.put("serviceName", "예약 상세");
|
|
||||||
insertMap.put("requestValue", String.valueOf(paramMap));
|
|
||||||
insertMap.put("responseValue", String.valueOf(map));
|
|
||||||
;
|
|
||||||
if(("true").equals(String.valueOf(map.get("success")))){
|
|
||||||
insertMap.put("resultCode", "SUCCESS");
|
|
||||||
}else{
|
|
||||||
insertMap.put("resultCode", "ERROR");
|
|
||||||
}
|
|
||||||
|
|
||||||
insertMap.put("resultMsg", String.valueOf(errorMsg));
|
|
||||||
|
|
||||||
// logHistoryService.insertLogHistory(insertMap, visitLogParamMap);
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
log.debug("WebServiceController selectReservationCnt END");
|
|
||||||
|
|
||||||
|
|
||||||
return HttpUtil.makeHashToJsonModelAndView(map);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 예약 저장
|
|
||||||
*
|
|
||||||
* @param request
|
|
||||||
* @param response
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
@RequestMapping(value="/webservice/insertReservation.do")
|
|
||||||
public ModelAndView insertReservation(HttpSession session, HttpServletRequest request, HttpServletResponse response) {
|
|
||||||
|
|
||||||
log.debug("WebServiceController insertReservation START");
|
|
||||||
|
|
||||||
HashMap<String, Object> paramMap = HttpUtil.getParameterMap(request);
|
|
||||||
HashMap<String, Object> map = new HashMap<String, Object>();
|
|
||||||
StringBuffer errorMsg = new StringBuffer();
|
|
||||||
|
|
||||||
try{
|
|
||||||
map = webServiceService.insertReservation(paramMap);
|
|
||||||
log.debug(map + "TEST");
|
|
||||||
}catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
errorMsg.append(e);
|
|
||||||
return null;
|
|
||||||
}finally {
|
|
||||||
if(Constants.OK == map.get("msgCode")) {
|
|
||||||
|
|
||||||
}else{
|
|
||||||
if(null == map.get("msgCode") || ("").equals(map.get("msgCode"))) {
|
|
||||||
map.put("msgCode", Constants.FAIL);
|
|
||||||
}
|
|
||||||
|
|
||||||
map.put("success", false);
|
|
||||||
if(null == map.get("msgDesc") || ("").equals(map.get("msgDesc"))) {
|
|
||||||
map.put("msgDesc","정상적으로 수행되지 않았습니다. 관리자에게 문의하시기 바랍니다. (E0029)");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
HashMap<String, Object> visitLogParamMap = RequestLogUtil.getVisitLogParameterMap(request);
|
|
||||||
HashMap<String, Object> insertMap = new HashMap<String, Object>();
|
|
||||||
|
|
||||||
insertMap.put("url", "/webservice/insertReservation.do");
|
|
||||||
insertMap.put("func", "selectReservationCnt");
|
|
||||||
insertMap.put("funcName", "예약 저장");
|
|
||||||
insertMap.put("service", "webServiceService");
|
|
||||||
insertMap.put("serviceName", "예약 저장");
|
|
||||||
insertMap.put("requestValue", String.valueOf(paramMap));
|
|
||||||
insertMap.put("responseValue", String.valueOf(map));
|
|
||||||
;
|
|
||||||
if(("true").equals(String.valueOf(map.get("success")))){
|
|
||||||
insertMap.put("resultCode", "SUCCESS");
|
|
||||||
}else{
|
|
||||||
insertMap.put("resultCode", "ERROR");
|
|
||||||
}
|
|
||||||
|
|
||||||
insertMap.put("resultMsg", String.valueOf(errorMsg));
|
|
||||||
|
|
||||||
// logHistoryService.insertLogHistory(insertMap, visitLogParamMap);
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
log.debug("WebServiceController insertReservation END");
|
|
||||||
|
|
||||||
|
|
||||||
return HttpUtil.makeHashToJsonModelAndView(map);
|
return HttpUtil.makeHashToJsonModelAndView(map);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
package com.madeuhome.dao.web.webreview;
|
||||||
|
|
||||||
|
import jakarta.annotation.PostConstruct;
|
||||||
|
import org.mybatis.spring.SqlSessionTemplate;
|
||||||
|
import org.mybatis.spring.support.SqlSessionDaoSupport;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.dao.DataAccessException;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public class WebReviewSqlMapDAO extends SqlSessionDaoSupport {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private SqlSessionTemplate sqlSessionTemplate;
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
void init() {
|
||||||
|
setSqlSessionTemplate(sqlSessionTemplate);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, Object> selectTotalProcedureReviewCount(HashMap<String, Object> paramMap)
|
||||||
|
throws DataAccessException {
|
||||||
|
return getSqlSession().selectOne("WebReview.selectTotalProcedureReviewCount", paramMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Map<String, Object>> selectListProcedureReview(HashMap<String, Object> paramMap)
|
||||||
|
throws DataAccessException {
|
||||||
|
return getSqlSession().selectList("WebReview.selectListProcedureReview", paramMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, Object> selectProcedureReview(HashMap<String, Object> paramMap) throws DataAccessException {
|
||||||
|
return getSqlSession().selectOne("WebReview.selectProcedureReview", paramMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateViewCount(HashMap<String, Object> paramMap) throws DataAccessException {
|
||||||
|
getSqlSession().update("WebReview.updateViewCount", paramMap);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -30,7 +30,8 @@ public class WebServiceSqlMapDAO extends SqlSessionDaoSupport{
|
|||||||
* @return
|
* @return
|
||||||
* @throws DataAccessException
|
* @throws DataAccessException
|
||||||
*/
|
*/
|
||||||
public List<Map<String, Object>> selectListWebCategory(HashMap<String, Object> paramMap) throws DataAccessException {
|
public List<Map<String, Object>> selectListWebCategory(HashMap<String, Object> paramMap)
|
||||||
|
throws DataAccessException {
|
||||||
logger.debug("WebServiceSqlMapDAO selectListWebCategory START");
|
logger.debug("WebServiceSqlMapDAO selectListWebCategory START");
|
||||||
|
|
||||||
String sqlId = "WebService.selectListWebCategory";
|
String sqlId = "WebService.selectListWebCategory";
|
||||||
@@ -90,56 +91,4 @@ public class WebServiceSqlMapDAO extends SqlSessionDaoSupport{
|
|||||||
|
|
||||||
return getSqlSession().selectList(sqlId, paramMap);
|
return getSqlSession().selectList(sqlId, paramMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 예약 상세 조회
|
|
||||||
*
|
|
||||||
* @param Map
|
|
||||||
* @return
|
|
||||||
* @throws DataAccessException
|
|
||||||
*/
|
|
||||||
public Map<String, Object> selectReservationCnt(HashMap<String, Object> paramMap) throws DataAccessException {
|
|
||||||
logger.debug("WebServiceSqlMapDAO selectReservationCnt START");
|
|
||||||
|
|
||||||
String sqlId = "WebService.selectReservationCnt";
|
|
||||||
|
|
||||||
logger.debug("WebServiceSqlMapDAO selectReservationCnt END");
|
|
||||||
|
|
||||||
return getSqlSession().selectOne(sqlId, paramMap);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 예약 시술 정보 조회
|
|
||||||
*
|
|
||||||
* @param Map
|
|
||||||
* @return
|
|
||||||
* @throws DataAccessException
|
|
||||||
*/
|
|
||||||
public Map<String, Object> selectReservationService(HashMap<String, Object> paramMap) throws DataAccessException {
|
|
||||||
logger.debug("WebServiceSqlMapDAO selectReservationService START");
|
|
||||||
|
|
||||||
String sqlId = "WebService.selectReservationService";
|
|
||||||
|
|
||||||
logger.debug("WebServiceSqlMapDAO selectReservationService END");
|
|
||||||
|
|
||||||
return getSqlSession().selectOne(sqlId, paramMap);
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* 예약 정보 저장
|
|
||||||
*
|
|
||||||
* @param Map
|
|
||||||
* @return
|
|
||||||
* @throws DataAccessException
|
|
||||||
*/
|
|
||||||
public Map<String, Object> insertReservation(HashMap<String, Object> paramMap) throws DataAccessException {
|
|
||||||
logger.debug("WebServiceSqlMapDAO insertReservation START");
|
|
||||||
|
|
||||||
String sqlId = "WebService.insertReservation";
|
|
||||||
|
|
||||||
logger.debug("WebServiceSqlMapDAO insertReservation END");
|
|
||||||
|
|
||||||
getSqlSession().insert(sqlId, paramMap);
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
40
src/main/java/com/madeuhome/dto/ReservationDto.java
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
package com.madeuhome.dto;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 예약 관련 DTO
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class ReservationDto {
|
||||||
|
// 예약 기본 정보
|
||||||
|
private String muReserveId;
|
||||||
|
private String userName;
|
||||||
|
private String phoneNumber;
|
||||||
|
private String birthDate;
|
||||||
|
private String selectedDate;
|
||||||
|
private String time;
|
||||||
|
private String etc;
|
||||||
|
|
||||||
|
// 시술 정보
|
||||||
|
private String categoryDivCd;
|
||||||
|
private String categoryNo;
|
||||||
|
private String postNo;
|
||||||
|
private String procedureId;
|
||||||
|
private String treatmentId;
|
||||||
|
private String treatmentName;
|
||||||
|
private String treatmentProcedureId;
|
||||||
|
private String treatmentProcedureName;
|
||||||
|
private String treatmentInfos;
|
||||||
|
|
||||||
|
// 병원 운영 정보
|
||||||
|
private String muHospitalId;
|
||||||
|
private String hospitalName;
|
||||||
|
private String searchDate;
|
||||||
|
private String openYn;
|
||||||
|
private String holidayYn;
|
||||||
|
private String openStartTime;
|
||||||
|
private String openEndTime;
|
||||||
|
private String breakStartTime;
|
||||||
|
private String breakEndTime;
|
||||||
|
}
|
||||||
@@ -0,0 +1,211 @@
|
|||||||
|
package com.madeuhome.service.web.reservation;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import org.mybatis.spring.SqlSessionTemplate;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.type.TypeReference;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.madeuhome.constants.Constants;
|
||||||
|
import com.madeuhome.util.OkHttpService;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 예약 서비스 (구현체 포함) - 쁘띠&피부센터
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
@Slf4j
|
||||||
|
public class ReservationService {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private SqlSessionTemplate sqlSession;
|
||||||
|
|
||||||
|
@Value("${url.old-crm-php}")
|
||||||
|
private String ocp;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 예약 시술 정보 조회
|
||||||
|
*/
|
||||||
|
public HashMap<String, Object> selectReservation(HashMap<String, Object> paramMap) throws Exception {
|
||||||
|
log.debug("ReservationService selectReservation START");
|
||||||
|
HashMap<String, Object> map = new HashMap<>();
|
||||||
|
|
||||||
|
try {
|
||||||
|
List<Map<String, Object>> listMap2 = new ArrayList<>();
|
||||||
|
|
||||||
|
if (paramMap.get("PROCEDURE_ID").toString().indexOf(",") != -1) {
|
||||||
|
String[] PROCEDURE_ID = paramMap.get("PROCEDURE_ID").toString().split(",");
|
||||||
|
for (int i = 0; i < PROCEDURE_ID.length; i++) {
|
||||||
|
HashMap<String, Object> map2 = new HashMap<>();
|
||||||
|
map2.put("PROCEDURE_ID", PROCEDURE_ID[i]);
|
||||||
|
listMap2.add(sqlSession.selectOne("Reservation.selectReservationService", map2));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
listMap2.add(sqlSession.selectOne("Reservation.selectReservationService", paramMap));
|
||||||
|
}
|
||||||
|
map.put("reservation", listMap2);
|
||||||
|
map.put("msgCode", Constants.OK);
|
||||||
|
map.put("success", "true");
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
|
||||||
|
log.debug("ReservationService selectReservation END");
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 병원 휴일 조회 (달력 표출용)
|
||||||
|
*/
|
||||||
|
public HashMap<String, Object> selectHospitalHolidayList(HashMap<String, Object> paramMap) throws Exception {
|
||||||
|
log.debug("ReservationService selectHospitalHolidayList START");
|
||||||
|
HashMap<String, Object> map = new HashMap<>();
|
||||||
|
|
||||||
|
try {
|
||||||
|
List<Map<String, Object>> listMap = sqlSession.selectList("Reservation.selectHospitalHolidayList",
|
||||||
|
paramMap);
|
||||||
|
map.put("rows", listMap);
|
||||||
|
map.put("msgCode", Constants.OK);
|
||||||
|
map.put("success", "true");
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
|
||||||
|
log.debug("ReservationService selectHospitalHolidayList END");
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 특정 날짜 운영시간 조회
|
||||||
|
*/
|
||||||
|
public HashMap<String, Object> selectHospitalWorkTime(HashMap<String, Object> paramMap) throws Exception {
|
||||||
|
log.debug("ReservationService selectHospitalWorkTime START");
|
||||||
|
HashMap<String, Object> map = new HashMap<>();
|
||||||
|
|
||||||
|
try {
|
||||||
|
Map<String, Object> result = sqlSession.selectOne("Reservation.selectHospitalWorkTime", paramMap);
|
||||||
|
if (result != null) {
|
||||||
|
map.put("rows", result);
|
||||||
|
} else {
|
||||||
|
map.put("rows", new HashMap<>());
|
||||||
|
}
|
||||||
|
map.put("msgCode", Constants.OK);
|
||||||
|
map.put("success", "true");
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
|
||||||
|
log.debug("ReservationService selectHospitalWorkTime END");
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 예약 카운트 조회
|
||||||
|
*/
|
||||||
|
public HashMap<String, Object> selectReservationCnt(HashMap<String, Object> paramMap) throws Exception {
|
||||||
|
log.debug("ReservationService selectReservationCnt START");
|
||||||
|
HashMap<String, Object> map = new HashMap<>();
|
||||||
|
|
||||||
|
try {
|
||||||
|
Map<String, Object> result = sqlSession.selectOne("Reservation.selectReservationCnt", paramMap);
|
||||||
|
map.put("rows", result);
|
||||||
|
map.put("msgCode", Constants.OK);
|
||||||
|
map.put("success", "true");
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
|
||||||
|
log.debug("ReservationService selectReservationCnt END");
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 예약 저장
|
||||||
|
*/
|
||||||
|
public HashMap<String, Object> insertReservation(HashMap<String, Object> paramMap) throws Exception {
|
||||||
|
log.debug("ReservationService insertReservation START");
|
||||||
|
HashMap<String, Object> map = new HashMap<>();
|
||||||
|
try {
|
||||||
|
String muReserveId = ("R").concat(String.valueOf(System.currentTimeMillis()));
|
||||||
|
paramMap.put("muReserveId", muReserveId);
|
||||||
|
ArrayList<String> userRequest = new ArrayList<>();
|
||||||
|
|
||||||
|
// TREATMENT_INFOS 파라미터가 있으면 파싱하여 P_변수명으로 세팅 후 insertReservation 호출
|
||||||
|
if (paramMap.get("TREATMENT_INFOS") != null) {
|
||||||
|
ObjectMapper objectMapper = new ObjectMapper();
|
||||||
|
List<Map<String, Object>> treatmentList = objectMapper.readValue(
|
||||||
|
paramMap.get("TREATMENT_INFOS").toString(),
|
||||||
|
new TypeReference<List<Map<String, Object>>>() {
|
||||||
|
});
|
||||||
|
for (Map<String, Object> t : treatmentList) {
|
||||||
|
paramMap.put("P_TREATMENT_ID", t.get("MU_TREATMENT_ID"));
|
||||||
|
paramMap.put("P_TREATMENT_NM", t.get("TREATMENT_NAME"));
|
||||||
|
paramMap.put("P_PROCEDURE_ID", t.get("MU_TREATMENT_PROCEDURE_ID"));
|
||||||
|
paramMap.put("P_PROCEDURE_NM", t.get("TREATMENT_PROCEDURE_NAME"));
|
||||||
|
userRequest.add((String) t.get("TREATMENT_PROCEDURE_NAME"));
|
||||||
|
sqlSession.insert("Reservation.insertReservation", paramMap);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 기존 방식대로 단일 시술 정보로 처리
|
||||||
|
paramMap.put("P_TREATMENT_ID", paramMap.get("MU_TREATMENT_ID"));
|
||||||
|
paramMap.put("P_TREATMENT_NM", paramMap.get("TREATMENT_NAME"));
|
||||||
|
paramMap.put("P_PROCEDURE_ID", paramMap.get("MU_TREATMENT_PROCEDURE_ID"));
|
||||||
|
paramMap.put("P_PROCEDURE_NM", paramMap.get("TREATMENT_PROCEDURE_NAME"));
|
||||||
|
userRequest.add((String) paramMap.get("TREATMENT_PROCEDURE_NAME"));
|
||||||
|
sqlSession.insert("Reservation.insertReservation", paramMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, String> formData = new HashMap<>();
|
||||||
|
formData.put("visitorName", (String) paramMap.get("NAME"));
|
||||||
|
formData.put("visitorPhone", (String) paramMap.get("PHONE_NUMBER"));
|
||||||
|
|
||||||
|
String strUserRequest = "[선택시술]:" + userRequest.stream().collect(Collectors.joining(", "));
|
||||||
|
String birthDate = "[생년월일]:" + paramMap.get("BIRTH_DATE");
|
||||||
|
String reqTxt = "[요청사항]:" + (String) paramMap.get("ETC");
|
||||||
|
formData.put("userRequest", strUserRequest + "\n" + birthDate + "\n" + reqTxt);
|
||||||
|
String time = (String) paramMap.get("TIME");
|
||||||
|
String date = (String) paramMap.get("SELECTED_DATE");
|
||||||
|
String dateTime = date + " " + time;
|
||||||
|
formData.put("datetime", dateTime);
|
||||||
|
|
||||||
|
Map<String, Object> detailMap = sqlSession.selectOne("Reservation.selectServiceDetail", paramMap);
|
||||||
|
|
||||||
|
formData.put("itemName", "[홈페이지] 쁘띠&피부센터");
|
||||||
|
// 구CRM 연동ID가 없을 경우 기본값 (피부 & 쁘띠센터)
|
||||||
|
String oldCrmItemId = (String) detailMap.get("oldCrmItemId") == null
|
||||||
|
? "NBI-4aJSJ67P-f0ID-4xds-aReQ-MnhfErLts0HP"
|
||||||
|
: (String) detailMap.get("oldCrmItemId");
|
||||||
|
formData.put("itemID", oldCrmItemId);
|
||||||
|
formData.put("etcText", "[진료]:" + (String) detailMap.get("CATEGORY_NM"));
|
||||||
|
|
||||||
|
// OLD CRM으로 예약정보 POST
|
||||||
|
OkHttpService.postFormData(ocp, formData);
|
||||||
|
|
||||||
|
map.put("msgCode", Constants.OK);
|
||||||
|
map.put("success", "true");
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
|
||||||
|
log.debug("ReservationService insertReservation END");
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -36,7 +36,7 @@ public class WebInstagramServiceImpl implements WebInstagramService {
|
|||||||
HashMap<String, Object> paramMap) throws Exception {
|
HashMap<String, Object> paramMap) throws Exception {
|
||||||
log.debug("WebInstagramServiceImpl selectListWebInstagram START");
|
log.debug("WebInstagramServiceImpl selectListWebInstagram START");
|
||||||
HashMap<String, Object> map = new HashMap<String, Object>();
|
HashMap<String, Object> map = new HashMap<String, Object>();
|
||||||
String apiUrl = "https://graph.instagram.com/" + clientId + "/media?fields=id,caption,media_url,permalink,media_type,thumbnail_url&access_token=" + accessToken;
|
String apiUrl = "https://graph.facebook.com/" + clientId + "/media?fields=id,caption,media_url,permalink,media_type,thumbnail_url&access_token=" + accessToken;
|
||||||
try{
|
try{
|
||||||
RestTemplate restTemplate = new RestTemplate();
|
RestTemplate restTemplate = new RestTemplate();
|
||||||
Map<String, Object> response = restTemplate.getForObject(apiUrl, Map.class);
|
Map<String, Object> response = restTemplate.getForObject(apiUrl, Map.class);
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package com.madeuhome.service.web.webreview;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
public interface WebReviewService {
|
||||||
|
public HashMap<String, Object> selectListProcedureReview(HashMap<String, Object> paramMap) throws Exception;
|
||||||
|
|
||||||
|
public HashMap<String, Object> selectProcedureReview(HashMap<String, Object> paramMap) throws Exception;
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
package com.madeuhome.service.web.webreview.impl;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import com.madeuhome.constants.Constants;
|
||||||
|
import com.madeuhome.dao.web.webreview.WebReviewSqlMapDAO;
|
||||||
|
import com.madeuhome.service.web.webreview.WebReviewService;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Service("WebReviewService")
|
||||||
|
public class WebReviewServiceImpl implements WebReviewService {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private WebReviewSqlMapDAO webReviewSqlMapDAO;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HashMap<String, Object> selectListProcedureReview(HashMap<String, Object> paramMap) throws Exception {
|
||||||
|
log.debug("WebReviewServiceImpl selectListProcedureReview START");
|
||||||
|
HashMap<String, Object> map = new HashMap<String, Object>();
|
||||||
|
try {
|
||||||
|
Map<String, Object> totalMap = webReviewSqlMapDAO.selectTotalProcedureReviewCount(paramMap);
|
||||||
|
map.put("totalCount", totalMap.get("totalCount"));
|
||||||
|
List<Map<String, Object>> listMap = webReviewSqlMapDAO.selectListProcedureReview(paramMap);
|
||||||
|
map.put("rows", listMap);
|
||||||
|
map.put("msgCode", Constants.OK);
|
||||||
|
map.put("success", "true");
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
log.debug("WebReviewServiceImpl selectListProcedureReview END");
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HashMap<String, Object> selectProcedureReview(HashMap<String, Object> paramMap) throws Exception {
|
||||||
|
log.debug("WebReviewServiceImpl selectProcedureReview START");
|
||||||
|
HashMap<String, Object> map = new HashMap<String, Object>();
|
||||||
|
try {
|
||||||
|
webReviewSqlMapDAO.updateViewCount(paramMap);
|
||||||
|
Map<String, Object> detailMap = webReviewSqlMapDAO.selectProcedureReview(paramMap);
|
||||||
|
map.put("rows", detailMap);
|
||||||
|
map.put("msgCode", Constants.OK);
|
||||||
|
map.put("success", "true");
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
log.debug("WebReviewServiceImpl selectProcedureReview END");
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,9 +4,8 @@ import java.util.HashMap;
|
|||||||
|
|
||||||
public interface WebServiceService {
|
public interface WebServiceService {
|
||||||
public HashMap<String, Object> selectListWebCategory(HashMap<String, Object> paramMap) throws Exception;
|
public HashMap<String, Object> selectListWebCategory(HashMap<String, Object> paramMap) throws Exception;
|
||||||
|
|
||||||
public HashMap<String, Object> selectListWebService(HashMap<String, Object> paramMap) throws Exception;
|
public HashMap<String, Object> selectListWebService(HashMap<String, Object> paramMap) throws Exception;
|
||||||
|
|
||||||
public HashMap<String, Object> selectServiceDetail(HashMap<String, Object> paramMap) throws Exception;
|
public HashMap<String, Object> selectServiceDetail(HashMap<String, Object> paramMap) throws Exception;
|
||||||
public HashMap<String, Object> selectReservation(HashMap<String, Object> paramMap) throws Exception;
|
|
||||||
public HashMap<String, Object> selectReservationCnt(HashMap<String, Object> paramMap) throws Exception;
|
|
||||||
public HashMap<String, Object> insertReservation(HashMap<String, Object> paramMap) throws Exception;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,22 +1,15 @@
|
|||||||
package com.madeuhome.service.web.webservice.impl;
|
package com.madeuhome.service.web.webservice.impl;
|
||||||
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import com.fasterxml.jackson.core.type.TypeReference;
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
||||||
import com.madeuhome.constants.Constants;
|
import com.madeuhome.constants.Constants;
|
||||||
import com.madeuhome.dao.web.webservice.WebServiceSqlMapDAO;
|
import com.madeuhome.dao.web.webservice.WebServiceSqlMapDAO;
|
||||||
import com.madeuhome.service.web.webservice.WebServiceService;
|
import com.madeuhome.service.web.webservice.WebServiceService;
|
||||||
import com.madeuhome.util.OkHttpService;
|
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
@@ -27,9 +20,6 @@ public class WebServiceServiceImpl implements WebServiceService{
|
|||||||
@Autowired
|
@Autowired
|
||||||
private WebServiceSqlMapDAO webServiceSqlMapDAO;
|
private WebServiceSqlMapDAO webServiceSqlMapDAO;
|
||||||
|
|
||||||
@Value("${url.old-crm-php}")
|
|
||||||
private String ocp;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 시술 정보 카테고리 리스트 조회 (List)
|
* 시술 정보 카테고리 리스트 조회 (List)
|
||||||
*
|
*
|
||||||
@@ -120,176 +110,4 @@ public class WebServiceServiceImpl implements WebServiceService{
|
|||||||
log.debug("WebServiceServiceImpl selectServiceDetail END");
|
log.debug("WebServiceServiceImpl selectServiceDetail END");
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 예약 정보 조회
|
|
||||||
*
|
|
||||||
* @param paramMap
|
|
||||||
* @return
|
|
||||||
* @throws Exception
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public HashMap<String, Object> selectReservation(HashMap<String, Object> paramMap) throws Exception {
|
|
||||||
log.debug("WebServiceServiceImpl selectReservation START");
|
|
||||||
HashMap<String, Object> map = new HashMap<String, Object>();
|
|
||||||
|
|
||||||
try{
|
|
||||||
//예약 목록
|
|
||||||
List<Map<String, Object>> listMap2 = new ArrayList<Map<String, Object>>();
|
|
||||||
|
|
||||||
if(paramMap.get("PROCEDURE_ID").toString().indexOf(",") != -1) {
|
|
||||||
String[] PROCEDURE_ID = paramMap.get("PROCEDURE_ID").toString().split(",");
|
|
||||||
|
|
||||||
for(int i = 0; i < PROCEDURE_ID.length; i++) {
|
|
||||||
HashMap<String, Object> map2 = new HashMap<String, Object>();
|
|
||||||
map2.put("PROCEDURE_ID", PROCEDURE_ID[i]);
|
|
||||||
listMap2.add(webServiceSqlMapDAO.selectReservationService(map2));
|
|
||||||
}
|
|
||||||
}else {
|
|
||||||
listMap2.add(webServiceSqlMapDAO.selectReservationService(paramMap));
|
|
||||||
}
|
|
||||||
map.put("reservation",listMap2);
|
|
||||||
map.put("msgCode", Constants.OK);
|
|
||||||
map.put("success","true");
|
|
||||||
|
|
||||||
}catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
|
|
||||||
log.debug("WebServiceServiceImpl selectReservation END");
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 예약 정보 조회
|
|
||||||
*
|
|
||||||
* @param paramMap
|
|
||||||
* @return
|
|
||||||
* @throws Exception
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public HashMap<String, Object> selectReservationCnt(HashMap<String, Object> paramMap) throws Exception {
|
|
||||||
log.debug("WebServiceServiceImpl selectReservationCnt START");
|
|
||||||
|
|
||||||
HashMap<String, Object> map = new HashMap<String, Object>();
|
|
||||||
|
|
||||||
try{
|
|
||||||
//상세 내용
|
|
||||||
Map<String, Object> listMap = webServiceSqlMapDAO.selectReservationCnt(paramMap);
|
|
||||||
map.put("rows",listMap);
|
|
||||||
|
|
||||||
map.put("msgCode", Constants.OK);
|
|
||||||
map.put("success","true");
|
|
||||||
|
|
||||||
}catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
|
|
||||||
log.debug("WebServiceServiceImpl selectReservationCnt END");
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 예약 정보 저장
|
|
||||||
*
|
|
||||||
* @param paramMap
|
|
||||||
* @return
|
|
||||||
* @throws Exception
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public HashMap<String, Object> insertReservation(HashMap<String, Object> paramMap) throws Exception {
|
|
||||||
log.debug("WebServiceServiceImpl insertReservation START");
|
|
||||||
HashMap<String, Object> map = new HashMap<String, Object>();
|
|
||||||
try{
|
|
||||||
String muReserveId = ("R").concat(String.valueOf(System.currentTimeMillis()));
|
|
||||||
paramMap.put("muReserveId",muReserveId);
|
|
||||||
ArrayList<String> userRequest = new ArrayList<String>();
|
|
||||||
// TREATMENT_INFOS 파라미터가 있으면 파싱하여 P_변수명으로 세팅 후 insertReservation 호출
|
|
||||||
if(paramMap.get("TREATMENT_INFOS") != null) {
|
|
||||||
ObjectMapper objectMapper = new ObjectMapper();
|
|
||||||
List<Map<String, Object>> treatmentList = objectMapper.readValue(paramMap.get("TREATMENT_INFOS").toString(), new TypeReference<List<Map<String, Object>>>(){});
|
|
||||||
for(Map<String, Object> t : treatmentList) {
|
|
||||||
paramMap.put("P_TREATMENT_ID", t.get("MU_TREATMENT_ID"));
|
|
||||||
paramMap.put("P_TREATMENT_NM", t.get("TREATMENT_NAME"));
|
|
||||||
paramMap.put("P_PROCEDURE_ID", t.get("MU_TREATMENT_PROCEDURE_ID"));
|
|
||||||
paramMap.put("P_PROCEDURE_NM", t.get("TREATMENT_PROCEDURE_NAME"));
|
|
||||||
userRequest.add((String) t.get("TREATMENT_PROCEDURE_NAME"));
|
|
||||||
webServiceSqlMapDAO.insertReservation(paramMap);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// 기존 방식대로 단일 시술 정보로 처리
|
|
||||||
paramMap.put("P_TREATMENT_ID", paramMap.get("MU_TREATMENT_ID"));
|
|
||||||
paramMap.put("P_TREATMENT_NM", paramMap.get("TREATMENT_NAME"));
|
|
||||||
paramMap.put("P_PROCEDURE_ID", paramMap.get("MU_TREATMENT_PROCEDURE_ID"));
|
|
||||||
paramMap.put("P_PROCEDURE_NM", paramMap.get("TREATMENT_PROCEDURE_NAME"));
|
|
||||||
userRequest.add((String) paramMap.get("TREATMENT_PROCEDURE_NAME"));
|
|
||||||
webServiceSqlMapDAO.insertReservation(paramMap);
|
|
||||||
}
|
|
||||||
|
|
||||||
Map<String, String> formData = new HashMap<>();
|
|
||||||
formData.put("visitorName", (String) paramMap.get("NAME"));
|
|
||||||
formData.put("visitorPhone", (String) paramMap.get("PHONE_NUMBER"));
|
|
||||||
|
|
||||||
String strUserRequest = "[선택시술]:" + userRequest.stream().collect(Collectors.joining(", "));
|
|
||||||
String birthDate = "[생년월일]:" + paramMap.get("BIRTH_DATE");
|
|
||||||
String reqTxt = "[요청사항]:" + (String) paramMap.get("ETC");
|
|
||||||
formData.put("userRequest", strUserRequest + "\n" + birthDate + "\n" + reqTxt);
|
|
||||||
String time = (String) paramMap.get("TIME");
|
|
||||||
String date = (String) paramMap.get("SELECTED_DATE");
|
|
||||||
String dateTime = date + " " + time;
|
|
||||||
formData.put("datetime", dateTime);
|
|
||||||
|
|
||||||
Map<String, Object> detailMap = webServiceSqlMapDAO.selectServiceDetail(paramMap);
|
|
||||||
|
|
||||||
formData.put("itemName", "[홈페이지] 쁘띠&피부센터");
|
|
||||||
// 구CRM 연동ID가 없을 경우 모두 (재방문) 다이어트 센터
|
|
||||||
String oldCrmItemId = (String) detailMap.get("oldCrmItemId") == null ? "NBI-4aJSJ67P-f0ID-4xds-aReQ-MnhfErLts0HP" : (String) detailMap.get("oldCrmItemId");
|
|
||||||
formData.put("itemID", oldCrmItemId);
|
|
||||||
|
|
||||||
formData.put("etcText", "[진료]:" + (String) detailMap.get("CATEGORY_NM"));
|
|
||||||
|
|
||||||
// OLD CRM으로 예약정보 POST
|
|
||||||
/**
|
|
||||||
* //시술정보(상품명 , 상품ID)
|
|
||||||
상품명 : 메쉬다주사(지방분해주사)
|
|
||||||
상품 ID : NBI-1M0JEq5C-b8LM-4W0V-9YxZ-Z5r9XWJpIVEZ
|
|
||||||
|
|
||||||
피부 & 쁘띠센터
|
|
||||||
NBI-4aJSJ67P-f0ID-4xds-aReQ-MnhfErLts0HP
|
|
||||||
|
|
||||||
프리미엄 레이저 리프팅
|
|
||||||
NBI-1iPCWjih-2TDk-4NG3-ci56-tK7dgxxAT6dU
|
|
||||||
|
|
||||||
(첫방문) 다이어트 센터
|
|
||||||
NBI-1Q8doiCm-qzTh-4imi-9lsK-6YDslUzIK2OO
|
|
||||||
|
|
||||||
(재방문) 다이어트 센터
|
|
||||||
NBI-2WlrXQdl-esws-5aA5-al7z-d7HwxL9tX0YF
|
|
||||||
|
|
||||||
탈모약
|
|
||||||
NBI-Nz00si0r-DkGc-5hdd-bs27-SLn0KHlHflS8
|
|
||||||
|
|
||||||
비만치료제 위고비
|
|
||||||
NBI-2nJnTFVm-ieDy-4TNQ-czDK-Ll9FyixFr7zn
|
|
||||||
|
|
||||||
*
|
|
||||||
*
|
|
||||||
**/
|
|
||||||
OkHttpService.postFormData(ocp, formData);
|
|
||||||
|
|
||||||
|
|
||||||
map.put("msgCode", Constants.OK);
|
|
||||||
map.put("success","true");
|
|
||||||
|
|
||||||
}catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
|
|
||||||
System.out.println("[insertReservation] paramMap: " + paramMap);
|
|
||||||
log.debug("WebServiceServiceImpl insertReservation END");
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -7,7 +7,7 @@ spring:
|
|||||||
password: madeu12#$
|
password: madeu12#$
|
||||||
|
|
||||||
url:
|
url:
|
||||||
cdn: http://dcrm.vara.co.kr/cdn/
|
cdn: https://newcrm.madeu.co.kr/cdn/
|
||||||
old-crm-php: http://crm.madeu.co.kr/add-booking-home.php
|
old-crm-php: http://crm.madeu.co.kr/add-booking-home.php
|
||||||
|
|
||||||
madeu:
|
madeu:
|
||||||
|
|||||||
@@ -2,12 +2,12 @@ spring:
|
|||||||
datasource:
|
datasource:
|
||||||
hikari:
|
hikari:
|
||||||
driver-class-name: org.mariadb.jdbc.Driver
|
driver-class-name: org.mariadb.jdbc.Driver
|
||||||
jdbc-url: jdbc:mariadb://vara.iptime.org:3306/madeu
|
jdbc-url: jdbc:mariadb://183.98.184.84:3306/madeu
|
||||||
username: madeu
|
username: madeu
|
||||||
password: madeu12#$
|
password: apdlemdb12#$
|
||||||
|
|
||||||
url:
|
url:
|
||||||
cdn: http://crm.vara.co.kr/cdn/
|
cdn: https://newcrm.madeu.co.kr/cdn/
|
||||||
old-crm-php: http://crm.madeu.co.kr/add-booking-home.php
|
old-crm-php: http://crm.madeu.co.kr/add-booking-home.php
|
||||||
|
|
||||||
madeu:
|
madeu:
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ spring:
|
|||||||
password: apdlemdb12#$
|
password: apdlemdb12#$
|
||||||
|
|
||||||
url:
|
url:
|
||||||
cdn: https://crm.vara.co.kr/cdn/
|
cdn: https://newcrm.madeu.co.kr/cdn/
|
||||||
old-crm-php: http://crm.madeu.co.kr/add-booking-home.php
|
old-crm-php: http://crm.madeu.co.kr/add-booking-home.php
|
||||||
|
|
||||||
madeu:
|
madeu:
|
||||||
|
|||||||
@@ -50,4 +50,4 @@ senderPhoneNumber: 025474711
|
|||||||
# Instagram 설정
|
# Instagram 설정
|
||||||
instagram:
|
instagram:
|
||||||
client-id: 17841400162629727
|
client-id: 17841400162629727
|
||||||
accesstoken: IGAAMzYDUuoLJBZAFBieGZAYWXplcjlkRGZAkenkxbDEtSWp0VDkxZA2VEOGljcndKR2NMWl9FQmNGUVlMTzZAkbWgxd0xjRXJlTjNhanB4VWxIX2tZARnhuZATUycEFoLVZAvbUtQam11blEzbDR6QmpjQVBBSm5wc0JKdnIyc2xxVVRrNAZDZD
|
accesstoken: EAAbtjekAF1EBQaZAZAmZCW8TyAA176J5yD6tFSj4MaZACgROAxGsvvT0cSvPxqLOHR4Bd8EeHSvWAqHZB8nHxurf3s3z0vtXt8sQ4zZBHpEJcnNTWSOvfch7hXv4uOQcfliBZCL6dDhMukAtgmXRHlfJasKDc5cZBcI7AuqNr1BZB0jUAwPC8uMUiIQ8dFjpRbnVyRwZDZD
|
||||||
|
|||||||
240
src/main/resources/mappers/ReservationMapper.xml
Normal file
@@ -0,0 +1,240 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||||
|
<mapper namespace="Reservation">
|
||||||
|
|
||||||
|
<!-- 병원 휴일 조회 (달력 표출용) -->
|
||||||
|
<select id="selectHospitalHolidayList" parameterType="hashmap" resultType="hashmap">
|
||||||
|
SELECT 'hospitalHoliday' AS "dateType"
|
||||||
|
, HOSPITAL_HOLIDAY_NAME AS "hospitalHolidayName"
|
||||||
|
, DATE_FORMAT(LOC_DATE, '%Y-%m-%d') AS "locDate"
|
||||||
|
FROM MU_HOSPITAL_HOLIDAY MH
|
||||||
|
WHERE MH.USE_YN = 'Y'
|
||||||
|
AND MH.MU_HOSPITAL_ID = (SELECT MU_HOSPITAL_ID FROM MU_HOSPITAL WHERE USE_YN='Y' AND CENTER_DIV_CD='PETIT' LIMIT 1)
|
||||||
|
AND (
|
||||||
|
(MH.REPEAT_YN = 'Y')
|
||||||
|
OR
|
||||||
|
(MH.REPEAT_YN = 'N' AND DATE_FORMAT( MH.LOC_DATE, '%Y' ) >= DATE_FORMAT( CURDATE( ), '%Y' ))
|
||||||
|
)
|
||||||
|
UNION ALL
|
||||||
|
(
|
||||||
|
SELECT 'publicHoliday' AS "dateType"
|
||||||
|
, MPH.PUBLIC_HOLIDAY_NAME AS "publicHolidayName"
|
||||||
|
, DATE_FORMAT(MPH.LOC_DATE, '%Y-%m-%d') AS "locDate"
|
||||||
|
FROM MU_PUBLIC_HOLIDAY MPH
|
||||||
|
JOIN MU_HOSPITAL MH
|
||||||
|
ON MH.MU_HOSPITAL_ID = (SELECT MU_HOSPITAL_ID FROM MU_HOSPITAL WHERE USE_YN='Y' AND CENTER_DIV_CD='PETIT' LIMIT 1)
|
||||||
|
AND MH.PUBLIC_HOLIDAY_USE_YN = 'Y'
|
||||||
|
WHERE MPH.USE_YN = 'Y'
|
||||||
|
AND DATE_FORMAT( MPH.LOC_DATE, '%Y' ) >= DATE_FORMAT( CURDATE( ), '%Y' )
|
||||||
|
)
|
||||||
|
UNION ALL
|
||||||
|
(
|
||||||
|
SELECT CASE WHEN OPEN_YN = 'Y' THEN 'hospitalScheduleOpen' ELSE 'hospitalSchedule' END AS "dateType"
|
||||||
|
, CASE WHEN OPEN_YN = 'Y' THEN '운영' ELSE '휴무' END AS "hospitalHolidayName"
|
||||||
|
, DATE_FORMAT(SCHEDULE_DATE, '%Y-%m-%d') AS "locDate"
|
||||||
|
FROM MU_HOSPITAL_SCHEDULE
|
||||||
|
WHERE MU_HOSPITAL_ID = (SELECT MU_HOSPITAL_ID FROM MU_HOSPITAL WHERE USE_YN='Y' AND CENTER_DIV_CD='PETIT' LIMIT 1)
|
||||||
|
AND USE_YN = 'Y'
|
||||||
|
AND DATE_FORMAT( SCHEDULE_DATE, '%Y' ) >= DATE_FORMAT( CURDATE( ), '%Y' )
|
||||||
|
)
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<!-- 특정 날짜 운영시간 조회 -->
|
||||||
|
<select id="selectHospitalWorkTime" parameterType="hashmap" resultType="hashmap">
|
||||||
|
SELECT MH.MU_HOSPITAL_ID AS "muHospitalId"
|
||||||
|
,MH.HOSPITAL_NAME AS "hospitalName"
|
||||||
|
,CASE
|
||||||
|
WHEN MHS.MU_HOSPITAL_SCHEDULE_ID IS NOT NULL THEN MHS.OPEN_YN
|
||||||
|
ELSE
|
||||||
|
CASE DAYOFWEEK(#{searchDate})
|
||||||
|
WHEN 2 THEN MH.MON_OPEN_YN
|
||||||
|
WHEN 3 THEN MH.TUE_OPEN_YN
|
||||||
|
WHEN 4 THEN MH.WED_OPEN_YN
|
||||||
|
WHEN 5 THEN MH.THU_OPEN_YN
|
||||||
|
WHEN 6 THEN MH.FRI_OPEN_YN
|
||||||
|
WHEN 7 THEN MH.SAT_OPEN_YN
|
||||||
|
WHEN 1 THEN MH.SUN_OPEN_YN
|
||||||
|
END
|
||||||
|
END AS "openYn"
|
||||||
|
,CASE
|
||||||
|
WHEN MHS.MU_HOSPITAL_SCHEDULE_ID IS NOT NULL AND MHS.OPEN_YN = 'Y' THEN 'N'
|
||||||
|
WHEN MHS.MU_HOSPITAL_SCHEDULE_ID IS NOT NULL AND MHS.OPEN_YN = 'N' THEN 'Y'
|
||||||
|
WHEN EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM MU_HOSPITAL_HOLIDAY HH
|
||||||
|
WHERE HH.USE_YN = 'Y'
|
||||||
|
AND HH.MU_HOSPITAL_ID = MH.MU_HOSPITAL_ID
|
||||||
|
AND (
|
||||||
|
(HH.REPEAT_YN = 'Y' AND DATE_FORMAT(HH.LOC_DATE, '%m-%d') = DATE_FORMAT(#{searchDate}, '%m-%d'))
|
||||||
|
OR
|
||||||
|
(HH.REPEAT_YN = 'N' AND HH.LOC_DATE = #{searchDate})
|
||||||
|
)) OR
|
||||||
|
EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM MU_PUBLIC_HOLIDAY MPH
|
||||||
|
WHERE MPH.USE_YN = 'Y'
|
||||||
|
AND MH.PUBLIC_HOLIDAY_USE_YN='Y'
|
||||||
|
AND MPH.LOC_DATE = #{searchDate}
|
||||||
|
)
|
||||||
|
THEN 'Y'
|
||||||
|
ELSE 'N'
|
||||||
|
END AS "holidayYn"
|
||||||
|
,CASE
|
||||||
|
WHEN MHS.MU_HOSPITAL_SCHEDULE_ID IS NOT NULL THEN MHS.OPEN_START_TIME
|
||||||
|
ELSE
|
||||||
|
CASE DAYOFWEEK(#{searchDate})
|
||||||
|
WHEN 2 THEN MH.MON_OPEN_START_TIME
|
||||||
|
WHEN 3 THEN MH.TUE_OPEN_START_TIME
|
||||||
|
WHEN 4 THEN MH.WED_OPEN_START_TIME
|
||||||
|
WHEN 5 THEN MH.THU_OPEN_START_TIME
|
||||||
|
WHEN 6 THEN MH.FRI_OPEN_START_TIME
|
||||||
|
WHEN 7 THEN MH.SAT_OPEN_START_TIME
|
||||||
|
WHEN 1 THEN MH.SUN_OPEN_START_TIME
|
||||||
|
END
|
||||||
|
END AS "openStartTime"
|
||||||
|
,CASE
|
||||||
|
WHEN MHS.MU_HOSPITAL_SCHEDULE_ID IS NOT NULL THEN MHS.OPEN_END_TIME
|
||||||
|
ELSE
|
||||||
|
CASE DAYOFWEEK(#{searchDate})
|
||||||
|
WHEN 2 THEN MH.MON_OPEN_END_TIME
|
||||||
|
WHEN 3 THEN MH.TUE_OPEN_END_TIME
|
||||||
|
WHEN 4 THEN MH.WED_OPEN_END_TIME
|
||||||
|
WHEN 5 THEN MH.THU_OPEN_END_TIME
|
||||||
|
WHEN 6 THEN MH.FRI_OPEN_END_TIME
|
||||||
|
WHEN 7 THEN MH.SAT_OPEN_END_TIME
|
||||||
|
WHEN 1 THEN MH.SUN_OPEN_END_TIME
|
||||||
|
END
|
||||||
|
END AS "openEndTime"
|
||||||
|
,CASE
|
||||||
|
WHEN MHS.MU_HOSPITAL_SCHEDULE_ID IS NOT NULL THEN MHS.BREAK_START_TIME
|
||||||
|
ELSE
|
||||||
|
CASE DAYOFWEEK(#{searchDate})
|
||||||
|
WHEN 2 THEN MH.MON_BREAK_START_TIME
|
||||||
|
WHEN 3 THEN MH.TUE_BREAK_START_TIME
|
||||||
|
WHEN 4 THEN MH.WED_BREAK_START_TIME
|
||||||
|
WHEN 5 THEN MH.THU_BREAK_START_TIME
|
||||||
|
WHEN 6 THEN MH.FRI_BREAK_START_TIME
|
||||||
|
WHEN 7 THEN MH.SAT_BREAK_START_TIME
|
||||||
|
WHEN 1 THEN MH.SUN_BREAK_START_TIME
|
||||||
|
END
|
||||||
|
END AS "breakStartTime"
|
||||||
|
,CASE
|
||||||
|
WHEN MHS.MU_HOSPITAL_SCHEDULE_ID IS NOT NULL THEN MHS.BREAK_END_TIME
|
||||||
|
ELSE
|
||||||
|
CASE DAYOFWEEK(#{searchDate})
|
||||||
|
WHEN 2 THEN MH.MON_BREAK_END_TIME
|
||||||
|
WHEN 3 THEN MH.TUE_BREAK_END_TIME
|
||||||
|
WHEN 4 THEN MH.WED_BREAK_END_TIME
|
||||||
|
WHEN 5 THEN MH.THU_BREAK_END_TIME
|
||||||
|
WHEN 6 THEN MH.FRI_BREAK_END_TIME
|
||||||
|
WHEN 7 THEN MH.SAT_BREAK_END_TIME
|
||||||
|
WHEN 1 THEN MH.SUN_BREAK_END_TIME
|
||||||
|
END
|
||||||
|
END AS "breakEndTime"
|
||||||
|
,MH.PUBLIC_HOLIDAY_USE_YN AS "publicHolidayUseYn"
|
||||||
|
FROM MU_HOSPITAL AS MH
|
||||||
|
LEFT JOIN MU_HOSPITAL_SCHEDULE MHS
|
||||||
|
ON MH.MU_HOSPITAL_ID = MHS.MU_HOSPITAL_ID
|
||||||
|
AND MHS.SCHEDULE_DATE = #{searchDate}
|
||||||
|
AND MHS.USE_YN = 'Y'
|
||||||
|
WHERE MH.USE_YN = 'Y'
|
||||||
|
AND MH.CENTER_DIV_CD = 'PETIT'
|
||||||
|
LIMIT 0, 1
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<!-- 예약 카운트 조회 -->
|
||||||
|
<select id="selectReservationCnt" resultType="hashmap" parameterType="hashmap">
|
||||||
|
SELECT COUNT(*) AS RES_CNT
|
||||||
|
FROM MU_RESERVE
|
||||||
|
WHERE RESERVE_DATE = #{SELECTED_DATE}
|
||||||
|
AND RESERVE_TIME = #{TIME}
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<!-- 예약 시술 정보 조회 -->
|
||||||
|
<select id="selectReservationService" resultType="hashmap" parameterType="hashmap">
|
||||||
|
SELECT A.TREATMENT_PROCEDURE_NAME, (B.PRICE + B.VAT) AS PRICE, B.VAT, B.DISCOUNT_PRICE, C.MU_TREATMENT_ID, C.TREATMENT_NAME, B.MU_TREATMENT_PROCEDURE_ID
|
||||||
|
FROM MU_TREATMENT_PROCEDURE A
|
||||||
|
LEFT OUTER JOIN MU_TREATMENT_PROCEDURE_PRICE B ON A.MU_TREATMENT_PROCEDURE_ID = B.MU_TREATMENT_PROCEDURE_ID AND B.USE_YN = 'Y'
|
||||||
|
LEFT OUTER JOIN MU_TREATMENT C ON A.MU_TREATMENT_ID = C.MU_TREATMENT_ID
|
||||||
|
WHERE A.MU_TREATMENT_PROCEDURE_ID = #{PROCEDURE_ID}
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<!-- 시술 상세 조회 (CRM 연동용) -->
|
||||||
|
<select id="selectServiceDetail" resultType="hashmap" parameterType="hashmap">
|
||||||
|
SELECT A.CATEGORY_DIV_CD
|
||||||
|
, A.CATEGORY_NO
|
||||||
|
, A.POST_NO
|
||||||
|
, C.CATEGORY_NM
|
||||||
|
, A.TITLE
|
||||||
|
, A.CONTENT
|
||||||
|
, A.THUMBNAIL_BOTTOM_TXT
|
||||||
|
, A.HASHTAG
|
||||||
|
, A.OLD_CRM_ITEM_ID as oldCrmItemId
|
||||||
|
, D.FILE_PATH AS THUMBNAIL_PATH
|
||||||
|
, E.FILE_PATH AS CONTENTS_PATH
|
||||||
|
, (SELECT MIN(PRICE + VAT) FROM MU_TREATMENT_PROCEDURE_PRICE C
|
||||||
|
LEFT OUTER JOIN HP_CONTENTS_BBS_PROCEDURE B ON A.POST_NO = B.POST_NO AND A.CATEGORY_DIV_CD = B.CATEGORY_DIV_CD AND A.CATEGORY_NO = B.CATEGORY_NO AND B.USE_YN = 'Y'
|
||||||
|
WHERE B.MU_TREATMENT_PROCEDURE_ID = C.MU_TREATMENT_PROCEDURE_ID AND C.USE_YN = 'Y') AS PRICE
|
||||||
|
, (SELECT MIN(DISCOUNT_PRICE) FROM MU_TREATMENT_PROCEDURE_PRICE C
|
||||||
|
LEFT OUTER JOIN HP_CONTENTS_BBS_PROCEDURE B ON A.POST_NO = B.POST_NO AND A.CATEGORY_DIV_CD = B.CATEGORY_DIV_CD AND A.CATEGORY_NO = B.CATEGORY_NO AND B.USE_YN = 'Y'
|
||||||
|
WHERE B.MU_TREATMENT_PROCEDURE_ID = C.MU_TREATMENT_PROCEDURE_ID AND C.USE_YN = 'Y') AS DISCOUNT_PRICE
|
||||||
|
FROM HP_CONTENTS_BBS A
|
||||||
|
LEFT OUTER JOIN HP_CATEGORY C ON A.CATEGORY_NO = C.CATEGORY_NO AND A.CATEGORY_DIV_CD = C.CATEGORY_DIV_CD
|
||||||
|
LEFT OUTER JOIN HP_ATTACH_FILE D ON A.THUMBNAIL_ATTACHFILE_ID = D.ATTACHFILE_ID
|
||||||
|
LEFT OUTER JOIN HP_ATTACH_FILE E ON A.CONTENTS_ATTACHFILE_ID = E.ATTACHFILE_ID
|
||||||
|
WHERE A.USE_YN = 'Y'
|
||||||
|
AND A.CATEGORY_DIV_CD = #{CATEGORY_DIV_CD}
|
||||||
|
AND A.CATEGORY_NO = #{CATEGORY_NO}
|
||||||
|
AND A.POST_NO = #{POST_NO}
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<!-- 예약 저장 -->
|
||||||
|
<insert id="insertReservation" parameterType="hashmap">
|
||||||
|
<selectKey resultType="string" keyProperty="id" order="BEFORE">
|
||||||
|
SELECT CONCAT(#{muReserveId},LPAD((SELECT NEXTVAL(MU_RESERVE_SEQ)), 11, 0))
|
||||||
|
</selectKey>
|
||||||
|
INSERT INTO MU_RESERVE(
|
||||||
|
MU_RESERVE_ID
|
||||||
|
,USER_NAME
|
||||||
|
,PHONE_NUMBER
|
||||||
|
,RESERVE_DATE
|
||||||
|
,RESERVE_TIME
|
||||||
|
,MU_TREATMENT_ID
|
||||||
|
,TREATMENT_NAME
|
||||||
|
,MU_TREATMENT_PROCEDURE_ID
|
||||||
|
,TREATMENT_PROCEDURE_NAME
|
||||||
|
,ETC
|
||||||
|
,STATUS
|
||||||
|
,STATUS2
|
||||||
|
,WRITE_DATE
|
||||||
|
,WRITE_TIME
|
||||||
|
,CUD_FLAG
|
||||||
|
,USE_YN
|
||||||
|
,REG_ID
|
||||||
|
,REG_DATE
|
||||||
|
,MOD_ID
|
||||||
|
,MOD_DATE
|
||||||
|
)VALUES(
|
||||||
|
#{id}
|
||||||
|
,#{NAME}
|
||||||
|
,#{PHONE_NUMBER}
|
||||||
|
,#{SELECTED_DATE}
|
||||||
|
,#{TIME}
|
||||||
|
,#{P_TREATMENT_ID}
|
||||||
|
,#{P_TREATMENT_NM}
|
||||||
|
,#{P_PROCEDURE_ID}
|
||||||
|
,#{P_PROCEDURE_NM}
|
||||||
|
,#{ETC,jdbcType=VARCHAR}
|
||||||
|
,'T'
|
||||||
|
,'N'
|
||||||
|
,CURDATE()
|
||||||
|
,CURTIME()
|
||||||
|
,'C'
|
||||||
|
,'Y'
|
||||||
|
,'customer'
|
||||||
|
,NOW()
|
||||||
|
,'customer'
|
||||||
|
,NOW()
|
||||||
|
)
|
||||||
|
</insert>
|
||||||
|
</mapper>
|
||||||
@@ -15,6 +15,8 @@
|
|||||||
<!-- 카테고리 상세 목록 조회 -->
|
<!-- 카테고리 상세 목록 조회 -->
|
||||||
<select id="selectListEvent" parameterType="hashmap" resultType="hashmap">
|
<select id="selectListEvent" parameterType="hashmap" resultType="hashmap">
|
||||||
SELECT A.CATEGORY_DIV_CD, A.CATEGORY_NO, A.POST_NO, TITLE, CONTENT, THUMBNAIL_BOTTOM_TXT, A.HASHTAG, D.FILE_PATH AS THUMBNAIL_PATH,
|
SELECT A.CATEGORY_DIV_CD, A.CATEGORY_NO, A.POST_NO, TITLE, CONTENT, THUMBNAIL_BOTTOM_TXT, A.HASHTAG, D.FILE_PATH AS THUMBNAIL_PATH,
|
||||||
|
DATE_FORMAT(A.EVENT_START_DT, '%Y-%m-%d') AS EVENT_START_DT,
|
||||||
|
DATE_FORMAT(A.EVENT_END_DT, '%Y-%m-%d') AS EVENT_END_DT,
|
||||||
(SELECT MIN(PRICE + VAT) FROM MU_TREATMENT_PROCEDURE_PRICE C
|
(SELECT MIN(PRICE + VAT) FROM MU_TREATMENT_PROCEDURE_PRICE C
|
||||||
LEFT OUTER JOIN HP_CONTENTS_BBS_PROCEDURE B ON A.POST_NO = B.POST_NO AND A.CATEGORY_DIV_CD = B.CATEGORY_DIV_CD AND A.CATEGORY_NO = B.CATEGORY_NO AND B.USE_YN = 'Y'
|
LEFT OUTER JOIN HP_CONTENTS_BBS_PROCEDURE B ON A.POST_NO = B.POST_NO AND A.CATEGORY_DIV_CD = B.CATEGORY_DIV_CD AND A.CATEGORY_NO = B.CATEGORY_NO AND B.USE_YN = 'Y'
|
||||||
WHERE B.MU_TREATMENT_PROCEDURE_ID = C.MU_TREATMENT_PROCEDURE_ID AND C.USE_YN = 'Y') AS PRICE,
|
WHERE B.MU_TREATMENT_PROCEDURE_ID = C.MU_TREATMENT_PROCEDURE_ID AND C.USE_YN = 'Y') AS PRICE,
|
||||||
@@ -26,12 +28,14 @@
|
|||||||
WHERE A.USE_YN = 'Y'
|
WHERE A.USE_YN = 'Y'
|
||||||
AND A.CATEGORY_DIV_CD = '04'
|
AND A.CATEGORY_DIV_CD = '04'
|
||||||
AND A.CATEGORY_NO = #{category_no}
|
AND A.CATEGORY_NO = #{category_no}
|
||||||
ORDER BY A.REG_DATE DESC
|
ORDER BY ORD_NO DESC
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<!-- 이벤트안내 상세 조회 -->
|
<!-- 이벤트안내 상세 조회 -->
|
||||||
<select id="selectEventDetail" resultType="hashmap" parameterType="hashmap">
|
<select id="selectEventDetail" resultType="hashmap" parameterType="hashmap">
|
||||||
SELECT A.CATEGORY_DIV_CD, A.CATEGORY_NO, A.POST_NO, C.CATEGORY_NM , TITLE, CONTENT, THUMBNAIL_BOTTOM_TXT, A.HASHTAG, D.FILE_PATH AS THUMBNAIL_PATH, E.FILE_PATH AS CONTENTS_PATH,
|
SELECT A.CATEGORY_DIV_CD, A.CATEGORY_NO, A.POST_NO, C.CATEGORY_NM , TITLE, CONTENT, THUMBNAIL_BOTTOM_TXT, A.HASHTAG, D.FILE_PATH AS THUMBNAIL_PATH, E.FILE_PATH AS CONTENTS_PATH,
|
||||||
|
DATE_FORMAT(A.EVENT_START_DT, '%Y-%m-%d') AS EVENT_START_DT,
|
||||||
|
DATE_FORMAT(A.EVENT_END_DT, '%Y-%m-%d') AS EVENT_END_DT,
|
||||||
(SELECT MIN(PRICE + VAT) FROM MU_TREATMENT_PROCEDURE_PRICE C
|
(SELECT MIN(PRICE + VAT) FROM MU_TREATMENT_PROCEDURE_PRICE C
|
||||||
LEFT OUTER JOIN HP_CONTENTS_BBS_PROCEDURE B ON A.POST_NO = B.POST_NO AND A.CATEGORY_DIV_CD = B.CATEGORY_DIV_CD AND A.CATEGORY_NO = B.CATEGORY_NO AND B.USE_YN = 'Y'
|
LEFT OUTER JOIN HP_CONTENTS_BBS_PROCEDURE B ON A.POST_NO = B.POST_NO AND A.CATEGORY_DIV_CD = B.CATEGORY_DIV_CD AND A.CATEGORY_NO = B.CATEGORY_NO AND B.USE_YN = 'Y'
|
||||||
WHERE B.MU_TREATMENT_PROCEDURE_ID = C.MU_TREATMENT_PROCEDURE_ID AND C.USE_YN = 'Y') AS PRICE,
|
WHERE B.MU_TREATMENT_PROCEDURE_ID = C.MU_TREATMENT_PROCEDURE_ID AND C.USE_YN = 'Y') AS PRICE,
|
||||||
|
|||||||
64
src/main/resources/mappers/WebReviewSqlMap.xml
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||||
|
<mapper namespace="WebReview">
|
||||||
|
|
||||||
|
<select id="selectTotalProcedureReviewCount" parameterType="hashmap" resultType="hashmap">
|
||||||
|
SELECT COUNT(*) AS "totalCount"
|
||||||
|
FROM MU_PROCEDURE_REVIEW MPR
|
||||||
|
WHERE MPR.USE_YN = 'Y'
|
||||||
|
AND MPR.CATEGORY_DIV_CD = #{categoryDivCd}
|
||||||
|
<if test="title != null and title != ''">
|
||||||
|
AND MPR.TITLE LIKE CONCAT('%', TRIM(#{title}), '%')
|
||||||
|
</if>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select id="selectListProcedureReview" parameterType="hashmap" resultType="hashmap">
|
||||||
|
SELECT MPR.*
|
||||||
|
FROM (
|
||||||
|
SELECT MPR.*
|
||||||
|
,CAST(@RNUM:=@RNUM + 1 AS CHAR) AS "rowNum"
|
||||||
|
FROM (
|
||||||
|
SELECT MPR.MU_PROCEDURE_REVIEW_ID AS "muProcedureReviewId"
|
||||||
|
,MPR.CATEGORY_DIV_CD AS "categoryDivCd"
|
||||||
|
,MPR.TITLE AS "title"
|
||||||
|
,MPR.CONTENT AS "summary"
|
||||||
|
,MPR.HASHTAG AS "hashtag"
|
||||||
|
,MPR.VIEW_COUNT AS "viewCount"
|
||||||
|
,DATE_FORMAT(MPR.REG_DATE, '%Y-%m-%d') AS "writeDate"
|
||||||
|
FROM MU_PROCEDURE_REVIEW MPR
|
||||||
|
WHERE MPR.USE_YN = 'Y'
|
||||||
|
AND MPR.CATEGORY_DIV_CD = #{categoryDivCd}
|
||||||
|
<if test="title != null and title != ''">
|
||||||
|
AND MPR.TITLE LIKE CONCAT('%', TRIM(#{title}), '%')
|
||||||
|
</if>
|
||||||
|
ORDER BY MPR.REG_DATE DESC
|
||||||
|
LIMIT 18446744073709551615
|
||||||
|
) MPR, (SELECT @RNUM:=0) R
|
||||||
|
WHERE 1 = 1
|
||||||
|
) MPR
|
||||||
|
WHERE 1 = 1
|
||||||
|
LIMIT ${start}, ${limit}
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select id="selectProcedureReview" parameterType="hashmap" resultType="hashmap">
|
||||||
|
SELECT MPR.MU_PROCEDURE_REVIEW_ID AS "muProcedureReviewId"
|
||||||
|
,MPR.CATEGORY_DIV_CD AS "categoryDivCd"
|
||||||
|
,MPR.TITLE AS "title"
|
||||||
|
,MPR.CONTENT AS "content"
|
||||||
|
,MPR.HASHTAG AS "hashtag"
|
||||||
|
,MPR.VIEW_COUNT AS "viewCount"
|
||||||
|
,DATE_FORMAT(MPR.REG_DATE, '%Y-%m-%d') AS "writeDate"
|
||||||
|
FROM MU_PROCEDURE_REVIEW MPR
|
||||||
|
WHERE MPR.USE_YN = 'Y'
|
||||||
|
AND MPR.MU_PROCEDURE_REVIEW_ID = #{muProcedureReviewId}
|
||||||
|
LIMIT 0, 1
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<update id="updateViewCount" parameterType="hashmap">
|
||||||
|
UPDATE MU_PROCEDURE_REVIEW
|
||||||
|
SET VIEW_COUNT = IFNULL(VIEW_COUNT, 0) + 1
|
||||||
|
WHERE USE_YN = 'Y'
|
||||||
|
AND MU_PROCEDURE_REVIEW_ID = #{muProcedureReviewId}
|
||||||
|
</update>
|
||||||
|
|
||||||
|
</mapper>
|
||||||
@@ -25,6 +25,7 @@
|
|||||||
WHERE A.USE_YN = 'Y'
|
WHERE A.USE_YN = 'Y'
|
||||||
AND A.CATEGORY_DIV_CD = '03'
|
AND A.CATEGORY_DIV_CD = '03'
|
||||||
AND A.CATEGORY_NO = #{categoryNo}
|
AND A.CATEGORY_NO = #{categoryNo}
|
||||||
|
ORDER BY ORD_NO DESC
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<!-- 카테고리 상세 조회 -->
|
<!-- 카테고리 상세 조회 -->
|
||||||
@@ -69,70 +70,4 @@
|
|||||||
AND A.POST_NO = #{POST_NO}
|
AND A.POST_NO = #{POST_NO}
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<!-- 예약 조회 -->
|
|
||||||
<select id="selectReservationCnt" resultType="hashmap" parameterType="hashmap">
|
|
||||||
SELECT COUNT(*) AS RES_CNT
|
|
||||||
FROM MU_RESERVE
|
|
||||||
WHERE RESERVE_DATE = #{SELECTED_DATE}
|
|
||||||
AND RESERVE_TIME = #{TIME}
|
|
||||||
</select>
|
|
||||||
|
|
||||||
<!-- 시술 목록 조회 -->
|
|
||||||
<select id="selectReservationService" resultType="hashmap" parameterType="hashmap">
|
|
||||||
SELECT A.TREATMENT_PROCEDURE_NAME, (B.PRICE + B.VAT) AS PRICE, B.VAT, B.DISCOUNT_PRICE, C.MU_TREATMENT_ID, C.TREATMENT_NAME, B.MU_TREATMENT_PROCEDURE_ID
|
|
||||||
FROM MU_TREATMENT_PROCEDURE A
|
|
||||||
LEFT OUTER JOIN MU_TREATMENT_PROCEDURE_PRICE B ON A.MU_TREATMENT_PROCEDURE_ID = B.MU_TREATMENT_PROCEDURE_ID AND B.USE_YN = 'Y'
|
|
||||||
LEFT OUTER JOIN MU_TREATMENT C ON A.MU_TREATMENT_ID = C.MU_TREATMENT_ID
|
|
||||||
WHERE A.MU_TREATMENT_PROCEDURE_ID = #{PROCEDURE_ID}
|
|
||||||
</select>
|
|
||||||
|
|
||||||
<!-- 예약 저장 -->
|
|
||||||
<insert id="insertReservation" parameterType="hashmap">
|
|
||||||
<selectKey resultType="string" keyProperty="id" order="BEFORE">
|
|
||||||
SELECT CONCAT(#{muReserveId},LPAD((SELECT NEXTVAL(MU_RESERVE_SEQ)), 11, 0))
|
|
||||||
</selectKey>
|
|
||||||
INSERT INTO MU_RESERVE(
|
|
||||||
MU_RESERVE_ID
|
|
||||||
,USER_NAME
|
|
||||||
,PHONE_NUMBER
|
|
||||||
,RESERVE_DATE
|
|
||||||
,RESERVE_TIME
|
|
||||||
,MU_TREATMENT_ID
|
|
||||||
,TREATMENT_NAME
|
|
||||||
,MU_TREATMENT_PROCEDURE_ID
|
|
||||||
,TREATMENT_PROCEDURE_NAME
|
|
||||||
,ETC
|
|
||||||
,STATUS
|
|
||||||
,STATUS2
|
|
||||||
,WRITE_DATE
|
|
||||||
,WRITE_TIME
|
|
||||||
,CUD_FLAG
|
|
||||||
,USE_YN
|
|
||||||
,REG_ID
|
|
||||||
,REG_DATE
|
|
||||||
,MOD_ID
|
|
||||||
,MOD_DATE
|
|
||||||
)VALUES(
|
|
||||||
#{id}
|
|
||||||
,#{NAME}
|
|
||||||
,#{PHONE_NUMBER}
|
|
||||||
,#{SELECTED_DATE}
|
|
||||||
,#{TIME}
|
|
||||||
,#{P_TREATMENT_ID}
|
|
||||||
,#{P_TREATMENT_NM}
|
|
||||||
,#{P_PROCEDURE_ID}
|
|
||||||
,#{P_PROCEDURE_NM}
|
|
||||||
,#{ETC,jdbcType=VARCHAR}
|
|
||||||
,'T'
|
|
||||||
,'N'
|
|
||||||
,CURDATE()
|
|
||||||
,CURTIME()
|
|
||||||
,'C'
|
|
||||||
,'Y'
|
|
||||||
,'customer'
|
|
||||||
,NOW()
|
|
||||||
,'customer'
|
|
||||||
,NOW()
|
|
||||||
)
|
|
||||||
</insert>
|
|
||||||
</mapper>
|
</mapper>
|
||||||
@@ -53,7 +53,7 @@ html { scroll-behavior:smooth; }
|
|||||||
|
|
||||||
/* 세로형 드롭다운 메뉴 - 타이트한 박스, 보더 제거 */
|
/* 세로형 드롭다운 메뉴 - 타이트한 박스, 보더 제거 */
|
||||||
.project_wrap header nav ul.depth1 li ul.depth2 {
|
.project_wrap header nav ul.depth1 li ul.depth2 {
|
||||||
width: 160px;
|
width: 180px;
|
||||||
height: auto;
|
height: auto;
|
||||||
padding: 8px 0;
|
padding: 8px 0;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
|||||||
@@ -1,435 +1,471 @@
|
|||||||
/* main_img */
|
* {
|
||||||
.project_wrap .same main .main_img .text_box > div { width:50%; }
|
box-sizing: border-box;
|
||||||
.project_wrap .same main .main_img .text_box .right_text_box p { font-size:52px; color:#000; }
|
|
||||||
.project_wrap .same main .main_img .text_box .right_text_box p span { font-weight:700; }
|
|
||||||
.project_wrap .same main .main_img .text_box .left_text_box p { color:#fff; }
|
|
||||||
.project_wrap .same main .main_img .text_box .left_text_box p span { color:#fff; }
|
|
||||||
/* content5 */
|
|
||||||
.project_wrap .same main .content5 { padding-bottom:0; }
|
|
||||||
|
|
||||||
/* 반응형 - 모바일 */
|
|
||||||
@media only screen and (max-width:768px){
|
|
||||||
/* main_img */
|
|
||||||
.project_wrap .same main .content5 { padding-bottom:0; }
|
|
||||||
.project_wrap .same main .main_img .text_box > div { width:100%; }
|
|
||||||
.project_wrap .same main .main_img .text_box .right_text_box { display:none; }
|
|
||||||
.project_wrap .same main .main_img .text_box .left_text_box p br { display:none; }
|
|
||||||
.project_wrap .same main .main_img .text_box .left_text_box p span { color:#000; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
.fix_area {
|
font-family: 'Noto Sans KR', sans-serif;
|
||||||
min-width: 1200px;
|
|
||||||
width: 1200px;
|
|
||||||
margin: 0 auto;
|
|
||||||
padding: 0 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-basic {
|
|
||||||
width:120px;
|
|
||||||
height:40px;
|
|
||||||
border: 1px solid #a73439;
|
|
||||||
border-radius:5px;
|
|
||||||
background-color: white;
|
|
||||||
color: #a73439;
|
|
||||||
}
|
|
||||||
|
|
||||||
.clear:after {
|
|
||||||
display: block;
|
|
||||||
visibility: hidden;
|
|
||||||
height: 0;
|
|
||||||
font-size: 0;
|
|
||||||
clear: both;
|
|
||||||
content: "";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.clear > .right {
|
|
||||||
float: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
.clear > .left{
|
|
||||||
float:left;
|
|
||||||
}
|
|
||||||
|
|
||||||
.main-img-size {
|
|
||||||
position: relative;
|
|
||||||
width: 655px;
|
|
||||||
height: 368px;
|
|
||||||
overflow: hidden;
|
|
||||||
border-radius: 0.25rem;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
.img_center img {
|
|
||||||
position: absolute;
|
|
||||||
top: 50%;
|
|
||||||
left: 50%;
|
|
||||||
transform: translate(-50%, -50%);
|
|
||||||
width: 100%;
|
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
background: #f7f7f9;
|
||||||
|
color: #222;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#service-header {
|
||||||
.thumbnail-bottom-txt {
|
|
||||||
padding-top: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.thumbnail-bottom-txt > span {
|
|
||||||
display: block;
|
|
||||||
color: #6c696a;
|
|
||||||
font-size: 13.5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.content>.wp60 {
|
|
||||||
width: 60%;
|
|
||||||
}
|
|
||||||
.content>.wp40 {
|
|
||||||
width: 40%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wp10{
|
|
||||||
width:10%;
|
|
||||||
}
|
|
||||||
.wp90{
|
|
||||||
width:90%;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.content>[class^=wp] {
|
|
||||||
float: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
.consultation-info h2{
|
|
||||||
font-size: 4rem;
|
|
||||||
}
|
|
||||||
.consultation-info p{
|
|
||||||
margin-top: 2rem;
|
|
||||||
font-size:2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.consultation-info .price {
|
|
||||||
display: block;
|
|
||||||
font-size: 3rem;
|
|
||||||
margin-top: 3rem;
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
}
|
|
||||||
.price-area .border-line {
|
|
||||||
height: 1px;
|
|
||||||
background-color: #ddd;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.hashtag_list{
|
|
||||||
padding: 1rem 0 1.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hashtag_list span{
|
|
||||||
font-size:1.6rem;
|
|
||||||
color:#a94442;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.procedure-area>.procedure_select_txt{
|
|
||||||
float: left;
|
|
||||||
width: 7rem;
|
|
||||||
line-height: 1.5;
|
|
||||||
padding-top: 0.375rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.procedure-area > .dropdown_area {
|
|
||||||
float: right;
|
|
||||||
width: calc(100% - 7rem);
|
|
||||||
}
|
|
||||||
|
|
||||||
.select_procedure_div {
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.select_procedure_div .default_item {
|
|
||||||
padding-top: 0.5rem;
|
|
||||||
padding-left: 0.5rem;
|
|
||||||
padding-bottom: 0.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.select_procedure_div .default_item {
|
|
||||||
position: relative;
|
|
||||||
width: 100%;
|
|
||||||
padding-right: 2.5rem;
|
|
||||||
background-color: #fff;
|
|
||||||
border: 1px solid #cb9f76;
|
|
||||||
text-align: left;
|
|
||||||
border-radius: 0;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.option_scrl_wrap {
|
|
||||||
display: none;
|
|
||||||
overflow: hidden;
|
|
||||||
position: relative;
|
|
||||||
z-index:1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.select_procedure_div.active .option_scrl_wrap {
|
|
||||||
border: 1px solid #76232f;
|
|
||||||
}
|
|
||||||
|
|
||||||
.select_service_form.active .default_item:after {
|
|
||||||
border-top-color: #333;
|
|
||||||
}
|
|
||||||
|
|
||||||
.default_item:after {
|
|
||||||
content: '';
|
|
||||||
display: block;
|
|
||||||
position: absolute;
|
|
||||||
top: 50%;
|
|
||||||
right: 1.1em;
|
|
||||||
margin-top: -0.2rem;
|
|
||||||
border: 0.28571428em solid transparent;
|
|
||||||
border-top-color: #999;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.optipon_item {
|
|
||||||
padding: 0.4rem 0.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sepr_wrap {
|
|
||||||
position: relative;
|
|
||||||
min-height: 2.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.item_subprice {
|
|
||||||
min-height: 42px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.select_procedure_div.active .option_scrl_wrap {
|
|
||||||
display: block;
|
|
||||||
position: absolute;
|
|
||||||
right: -1px;
|
|
||||||
left: -1px;
|
|
||||||
background-color: #fff;
|
|
||||||
user-select: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cs-checkbox > label.d-block {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
.cs-checkbox > label {
|
|
||||||
position: relative;
|
|
||||||
display: inline-block;
|
|
||||||
cursor: pointer;
|
|
||||||
padding-left: 30px;
|
|
||||||
margin: 0;
|
|
||||||
line-height: 20px;
|
|
||||||
transition: color .3s ease-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.oi-wrap {
|
|
||||||
display: -webkit-box;
|
|
||||||
display: -ms-flexbox;
|
|
||||||
display: flex;
|
|
||||||
-webkit-box-pack: justify;
|
|
||||||
-ms-flex-pack: justify;
|
|
||||||
justify-content: space-between;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* .cs-checkbox input[type="checkbox"] { */
|
|
||||||
/* visibility: hidden; */
|
|
||||||
/* display: none; */
|
|
||||||
/* } */
|
|
||||||
|
|
||||||
/* .cs-checkbox > label:before, .cs-radio > .r_visible { */
|
|
||||||
/* border: 1px solid #ccc; */
|
|
||||||
/* } */
|
|
||||||
|
|
||||||
input[type="checkbox"] {
|
|
||||||
transform: scale(1.5); /* 크기를 1.5배로 확대 */
|
|
||||||
}
|
|
||||||
|
|
||||||
.idxChk{
|
|
||||||
position:absolute;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cs-checkbox > label:before {
|
|
||||||
content: "";
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
display: inline-block;
|
|
||||||
margin-right: 0.8em;
|
|
||||||
border-radius: 0;
|
|
||||||
background-color: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.oi-wrap .oi-txt {
|
|
||||||
flex: 0 0 65%;
|
|
||||||
max-width: 65%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.option_list {
|
|
||||||
display: block;
|
|
||||||
background: #fff;
|
background: #fff;
|
||||||
max-height: 224px;
|
border-bottom: 1px solid #ececec;
|
||||||
overflow-y: auto;
|
padding: 14px 0 14px 24px;
|
||||||
overflow-x: hidden;
|
font-size: 0.98em;
|
||||||
|
color: #888;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.main-wrap {
|
||||||
.oi-wrap .oi-price {
|
max-width: 1280px;
|
||||||
flex: 0 0 35%;
|
margin: 0 auto;
|
||||||
max-width: 35%;
|
background: #fff;
|
||||||
text-align: right;
|
border-radius: 18px;
|
||||||
|
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.07);
|
||||||
|
margin-top: 32px;
|
||||||
|
padding: 0 0 32px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.original_price {
|
.top-section {
|
||||||
color: #757575;
|
display: flex;
|
||||||
opacity: 0.7;
|
flex-wrap: wrap;
|
||||||
|
gap: 32px;
|
||||||
|
padding: 32px 32px 0 32px;
|
||||||
|
align-items: flex-start;
|
||||||
}
|
}
|
||||||
|
|
||||||
.d-block {
|
.img-box {
|
||||||
display: block;
|
border-radius: 18px;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.discount_price {
|
.img-box img {
|
||||||
font-family: 'Campton', Sans-serif;
|
width: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
border-radius: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-box {
|
||||||
|
flex: 1 1 300px;
|
||||||
|
min-width: 240px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-title {
|
||||||
|
font-size: 1.7em;
|
||||||
|
font-weight: 700;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
color: #222;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-desc {
|
||||||
|
color: #444;
|
||||||
|
font-size: 1.1em;
|
||||||
|
margin-bottom: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.event-period {
|
||||||
|
font-size: 1.05em;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: #A73439;
|
color: #e74c3c;
|
||||||
|
background: #fef2f2;
|
||||||
|
border: 1px solid #fecaca;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 10px 14px;
|
||||||
|
margin-bottom: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.procedure-area:after {
|
.info-price {
|
||||||
|
font-size: 1.2em;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #b23c3c;
|
||||||
|
margin-bottom: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.select-row {
|
||||||
|
margin-bottom: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.select-row label {
|
||||||
|
font-weight: 500;
|
||||||
|
margin-bottom: 8px;
|
||||||
display: block;
|
display: block;
|
||||||
visibility: hidden;
|
|
||||||
height: 0;
|
|
||||||
font-size: 0;
|
|
||||||
clear: both;
|
|
||||||
content: "";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.selected-procedure{
|
.total-row {
|
||||||
margin-top:20px;
|
display: flex;
|
||||||
position:relative;
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 1.1em;
|
||||||
|
margin-bottom: 18px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.total-row .total-label {
|
||||||
.selected-procedure .selt_info_wrap .info {
|
color: #888;
|
||||||
top: 0.7rem;
|
|
||||||
width: 9.5em;
|
|
||||||
padding-top: 0.3em;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.selt_info_wrap .info {
|
.total-row .total-price {
|
||||||
position: absolute;
|
font-weight: bold;
|
||||||
top: 0.2rem;
|
color: #b23c3c;
|
||||||
right: 0.2rem;
|
|
||||||
width: 8.5em;
|
|
||||||
padding-right: 1rem;
|
|
||||||
padding-top: 0.2em;
|
|
||||||
text-align: right;
|
|
||||||
}
|
}
|
||||||
.selt_info_wrap .info button{
|
|
||||||
|
.reserve-btn {
|
||||||
|
width: 100%;
|
||||||
|
padding: 14px 0;
|
||||||
|
background: #b23c3c;
|
||||||
|
color: #fff;
|
||||||
border: none;
|
border: none;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-size: 1.1em;
|
||||||
|
font-weight: bold;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background 0.15s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.reserve-btn:disabled {
|
||||||
|
background: #ddd;
|
||||||
|
color: #888;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.desc-section {
|
||||||
|
margin-top: 36px;
|
||||||
|
padding: 0 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.desc-title {
|
||||||
|
font-size: 1.25em;
|
||||||
|
font-weight: 700;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
color: #222;
|
||||||
|
}
|
||||||
|
|
||||||
|
.desc-content {
|
||||||
|
color: #444;
|
||||||
|
font-size: 1.05em;
|
||||||
|
line-height: 1.7;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hashtag-section {
|
||||||
|
margin-top: 30px;
|
||||||
|
padding: 20px 0;
|
||||||
|
border-top: 1px solid #eee;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hashtag-container {
|
||||||
|
max-width: 1200px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 0 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hashtag-list {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hashtag {
|
||||||
|
display: inline-block;
|
||||||
|
background-color: #f8f9fa;
|
||||||
|
color: #495057;
|
||||||
|
padding: 8px 15px;
|
||||||
|
border-radius: 20px;
|
||||||
|
font-size: 14px;
|
||||||
|
text-decoration: none;
|
||||||
|
border: 1px solid #dee2e6;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hashtag:hover {
|
||||||
|
background-color: #007bff;
|
||||||
|
color: white;
|
||||||
|
border-color: #007bff;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
#thumbnail-bottom-txt {
|
||||||
|
padding: 8px;
|
||||||
|
margin-top: 10px;
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Choices.js 커스터마이징 - 개선된 버전 */
|
||||||
.real_price {
|
.choices {
|
||||||
font-family: 'Campton', Sans-serif;
|
border: 1px solid #ddd !important;
|
||||||
font-weight: 600;
|
border-radius: 6px !important;
|
||||||
color: #A73439;
|
font-size: 1em !important;
|
||||||
|
background: #fff !important;
|
||||||
|
min-width: 300px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.selected-procedure .selt_info_wrap {
|
.choices__inner {
|
||||||
padding: 0.8rem 0;
|
background: #fff !important;
|
||||||
z-index:0;
|
padding: 8px 12px !important;
|
||||||
|
min-height: 40px !important;
|
||||||
|
color: #222 !important;
|
||||||
|
min-width: 280px !important;
|
||||||
|
width: 100% !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.selt_info_wrap {
|
/* 플레이스홀더 텍스트 잘림 방지 */
|
||||||
position: relative;
|
.choices__placeholder {
|
||||||
min-height: 2.5rem;
|
color: #888 !important;
|
||||||
background-color:#fff;
|
opacity: 1 !important;
|
||||||
border:1px solid #eee;
|
width: 100% !important;
|
||||||
|
min-width: 200px !important;
|
||||||
|
white-space: nowrap !important;
|
||||||
|
overflow: visible !important;
|
||||||
|
text-overflow: clip !important;
|
||||||
|
display: block !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.selected-procedure .selt_info_wrap .selt {
|
.choices__input {
|
||||||
padding-right: 9.5em;
|
color: #222 !important;
|
||||||
padding-left: 1rem;
|
background: transparent !important;
|
||||||
|
min-width: 200px !important;
|
||||||
|
width: 100% !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.choices__input::placeholder {
|
||||||
|
color: #888 !important;
|
||||||
|
opacity: 1 !important;
|
||||||
|
width: 100% !important;
|
||||||
|
min-width: 200px !important;
|
||||||
|
white-space: nowrap !important;
|
||||||
|
overflow: visible !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 다중 선택시 입력 필드 너비 확보 */
|
||||||
|
.choices[data-type*="select-multiple"] .choices__input {
|
||||||
|
min-width: 200px !important;
|
||||||
|
width: auto !important;
|
||||||
|
flex: 1 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 선택된 항목들과 입력 필드 공간 분배 */
|
||||||
|
.choices__list--multiple {
|
||||||
|
flex-wrap: wrap !important;
|
||||||
|
align-items: center !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.choices__list--multiple:empty+.choices__input {
|
||||||
|
min-width: 200px !important;
|
||||||
|
width: 100% !important;
|
||||||
|
flex: 1 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 선택된 항목의 가격 표시 스타일 */
|
||||||
|
.selected-item-content {
|
||||||
|
display: flex !important;
|
||||||
|
flex-direction: column !important;
|
||||||
|
align-items: flex-start !important;
|
||||||
|
flex: 1 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected-item-name {
|
||||||
|
font-weight: 500 !important;
|
||||||
|
margin-bottom: 2px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected-item-price {
|
||||||
|
font-size: 0.85em !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected-price {
|
||||||
|
color: #b23c3c !important;
|
||||||
|
font-weight: bold !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected-price-discount {
|
||||||
|
color: #b23c3c !important;
|
||||||
|
font-weight: bold !important;
|
||||||
|
font-size: 0.9em !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected-price-original {
|
||||||
|
color: #aaa !important;
|
||||||
|
font-size: 0.85em !important;
|
||||||
|
text-decoration: line-through !important;
|
||||||
|
margin-left: 4px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 선택된 항목들 스타일 수정 */
|
||||||
|
.choices__list--multiple .choices__item {
|
||||||
|
background-color: #f8f9fa !important;
|
||||||
|
border: 1px solid #dee2e6 !important;
|
||||||
|
border-radius: 16px !important;
|
||||||
|
padding: 8px 12px !important;
|
||||||
|
margin: 2px !important;
|
||||||
|
font-size: 0.9em !important;
|
||||||
|
color: #495057 !important;
|
||||||
|
flex-shrink: 0 !important;
|
||||||
|
display: flex !important;
|
||||||
|
align-items: center !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 빨간색으로 변경 */
|
||||||
|
.choices__button {
|
||||||
|
background-image: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjEiIGhlaWdodD0iMjEiIHZpZXdCb3g9IjAgMCAyMSAyMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48ZyBmaWxsPSIjYjIzYzNjIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiPjxwYXRoIGQ9Ik0yLjU5Mi4wNDRsMTguMzY0IDE4LjM2NC0yLjU0OCAyLjU0OEwuMDQ0IDIuNTkyeiIvPjxwYXRoIGQ9Ik0wIDE4LjM2NEwxOC4zNjQgMGwyLjU0OCAyLjU0OEwyLjU0OCAyMC45MTJ6Ii8+PC9nPjwvc3ZnPg==') !important;
|
||||||
|
background-size: 14px 14px !important;
|
||||||
|
background-position: center !important;
|
||||||
|
background-repeat: no-repeat !important;
|
||||||
|
border-left: 0 !important;
|
||||||
|
margin: 0 !important;
|
||||||
|
padding: 0 !important;
|
||||||
|
width: 14px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 드롭다운 컨테이너 */
|
||||||
|
.choices__list--dropdown {
|
||||||
|
background: #fff !important;
|
||||||
|
border: 1px solid #ddd !important;
|
||||||
|
border-radius: 6px !important;
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 드롭다운 옵션들 스타일 */
|
||||||
|
.choices__list--dropdown .choices__item {
|
||||||
|
padding: 8px 12px !important;
|
||||||
|
display: flex !important;
|
||||||
|
justify-content: space-between !important;
|
||||||
|
align-items: center !important;
|
||||||
|
color: #222 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.choices__list--dropdown .choices__item--selectable:hover {
|
||||||
|
background-color: #f5f5f5 !important;
|
||||||
|
color: #222 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.choices__list--dropdown .choices__item--highlighted {
|
||||||
|
background-color: #b23c3c !important;
|
||||||
|
color: #fff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 포커스 상태 */
|
||||||
|
.choices.is-focused .choices__inner {
|
||||||
|
border-color: #b23c3c !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 가격 표시 스타일 */
|
||||||
|
.procedure-price {
|
||||||
|
color: #b23c3c !important;
|
||||||
|
font-weight: bold !important;
|
||||||
|
font-size: 0.9em !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.procedure-price-discount {
|
||||||
|
color: #b23c3c !important;
|
||||||
|
font-weight: bold !important;
|
||||||
|
font-size: 0.9em !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.procedure-price-original {
|
||||||
|
color: #aaa !important;
|
||||||
|
font-size: 0.85em !important;
|
||||||
|
text-decoration: line-through !important;
|
||||||
|
margin-left: 4px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 드롭다운이 열렸을 때 하이라이트된 항목의 가격 색상 */
|
||||||
|
.choices__list--dropdown .choices__item--highlighted .procedure-price,
|
||||||
|
.choices__list--dropdown .choices__item--highlighted .procedure-price-discount {
|
||||||
|
color: #fff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.choices__list--dropdown .choices__item--highlighted .procedure-price-original {
|
||||||
|
color: #ddd !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 검색 입력창 스타일 */
|
||||||
|
.choices[data-type*="select-multiple"] .choices__input {
|
||||||
|
background-color: transparent !important;
|
||||||
|
color: #222 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 비활성화 상태 */
|
||||||
|
.choices.is-disabled .choices__inner {
|
||||||
|
background-color: #f8f9fa !important;
|
||||||
|
color: #6c757d !important;
|
||||||
|
cursor: not-allowed !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 반응형 대응 */
|
||||||
|
@media (max-width: 600px) {
|
||||||
|
.choices {
|
||||||
|
min-width: 250px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.choices__inner {
|
||||||
|
min-width: 230px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.choices__placeholder,
|
||||||
|
.choices__input,
|
||||||
|
.choices__input::placeholder {
|
||||||
|
min-width: 150px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.choices__list--multiple .choices__item {
|
||||||
|
max-width: 250px !important;
|
||||||
|
padding: 6px 10px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected-item-name {
|
||||||
|
font-size: 0.9em !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected-item-price {
|
||||||
|
font-size: 0.8em !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.choices__list--multiple .choices__item[data-deletable] .choices__button {
|
||||||
|
width: 20px !important;
|
||||||
|
height: 20px !important;
|
||||||
|
font-size: 16px !important;
|
||||||
|
text-indent: 0 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 900px) {
|
||||||
|
.main-wrap {
|
||||||
|
margin-top: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-section {
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 18px;
|
||||||
|
padding: 20px 10px 0 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.img-box {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.selt_info_wrap .selt {
|
.info-box {
|
||||||
padding-top: 0.3em;
|
min-width: unset;
|
||||||
padding-right: 8.5em;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.total-price-area .total {
|
.desc-section {
|
||||||
position: relative;
|
padding: 0 10px;
|
||||||
background-color: #e6e6e6;
|
}
|
||||||
padding: 25px 25px 60px;
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.total-price-area .total .txt_sub {
|
@media (max-width: 600px) {
|
||||||
color: #222222;
|
.main-wrap {
|
||||||
font-size: 2rem;
|
margin-top: 0;
|
||||||
opacity: 1;
|
border-radius: 0;
|
||||||
}
|
box-shadow: none;
|
||||||
.total-price-area .total .right strong {
|
|
||||||
font-size: 22px;
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.total-price-area .total-price-txt {
|
.top-section {
|
||||||
font-family: 'Campton', Sans-serif;
|
padding: 12px 2vw 0 2vw;
|
||||||
font-weight: 600;
|
|
||||||
color: #A73439;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.total-price-area .total .bs-txt {
|
.desc-section {
|
||||||
position: absolute;
|
padding: 0 2vw;
|
||||||
bottom: 17px;
|
|
||||||
right: 25px;
|
|
||||||
display: block;
|
|
||||||
margin-top: 4px;
|
|
||||||
font-size: 12px;
|
|
||||||
color: #999999;
|
|
||||||
letter-spacing: -1px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.main_btn {
|
|
||||||
text-align: right;
|
|
||||||
margin: 1rem 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.main_btn button {
|
|
||||||
width: 180px;
|
|
||||||
height: 50px;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.fastrack-btn {
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-primary {
|
|
||||||
border: 1px solid #a73439;
|
|
||||||
background-color: #a73439;
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.img-content{
|
|
||||||
background-color: #eee;
|
|
||||||
}
|
|
||||||
|
|
||||||
.img-area{
|
|
||||||
padding-top: 70px;
|
|
||||||
padding-bottom: 200px;
|
|
||||||
text-align:center;
|
|
||||||
}
|
}
|
||||||
@@ -1,110 +1,495 @@
|
|||||||
/* main_img */
|
* {
|
||||||
.project_wrap .same main .main_img .text_box > div { width:50%; }
|
box-sizing: border-box;
|
||||||
.project_wrap .same main .main_img .text_box .right_text_box p { font-size:52px; color:#000; }
|
|
||||||
.project_wrap .same main .main_img .text_box .right_text_box p span { font-weight:700; }
|
|
||||||
.project_wrap .same main .main_img .text_box .left_text_box p { color:#fff; }
|
|
||||||
.project_wrap .same main .main_img .text_box .left_text_box p span { color:#fff; }
|
|
||||||
/* content5 */
|
|
||||||
.project_wrap .same main .content5 { padding-bottom:0; }
|
|
||||||
|
|
||||||
.project_wrap .same aside {background: white; width: 30%; top: 12%;}
|
|
||||||
.project_wrap .same aside ul{position: fixed; left: 5%; width: 19%;}
|
|
||||||
.project_wrap .same aside ul li{margin-bottom: 0.5rem; margin-top: 0px;}
|
|
||||||
.project_wrap .same aside .first {padding-top: 1rem; padding-bottom: 1rem;}
|
|
||||||
.project_wrap .same aside .nonactive {border: 1px solid #d8d8d8; background-color: #f9f9fb;}
|
|
||||||
.project_wrap .same aside .active {border: 1px solid #d8d8d8; color: #a73439; background-color: rgba(118, 35, 47, 0); border-left: 2px solid #a73439;}
|
|
||||||
.project_wrap .same aside ul a{padding-left: 10px;}
|
|
||||||
.project_wrap .same main {width: 60%; padding-top: 7%;}
|
|
||||||
.project_wrap .same main ul{padding-top: 2%; width:102%;}
|
|
||||||
.event-card-list > ul { display: block; list-style-type: disc; margin-block-start: 1em; margin-block-end: 1em; padding-inline-start: 40px; unicode-bidi: isolate; }
|
|
||||||
.event-card-list > li { margin-bottom: 70px; opacity: 1;}
|
|
||||||
.event-card-list .event-card { display: block; position: relative; width: 775px; height: 196px; padding-right: 10px; margin-left: auto; overflow: hidden;}
|
|
||||||
.event-card .img_box { position: relative; width: 350px; height: 100%; background-color: black; float: left; overflow: hidden; }
|
|
||||||
.event-card .img_box img { position: absolute; min-width: 100%; min-height: 100%; width: 100%; height: 100%; margin: auto; top: 0; bottom: 0; left: 0; right: 0; opacity: 1; transform: scale(1); transition: .4s ease-out;}
|
|
||||||
.event-card .txt-box { position: relative; padding-top: 115px; width: 343px; height: 100%; float: right;}
|
|
||||||
.event-card .txt-box .tit-txt { position: absolute; left: 0; bottom: 88px;}
|
|
||||||
.txt-box .tit-txt > p { margin: 0; font-size: 22px; font-weight: 500; line-height: 1.3;}
|
|
||||||
.event-card .txt-box > .sub-txt { font-size: 12px;}
|
|
||||||
.one-ellip { position: relative;overflow: hidden; white-space: nowrap; text-overflow: ellipsis; left: 0%; width: 100%;-webkit-transition: left 3s, width 3s; -moz-transition: left 3s, width 3s; transition: left 3s, width 3s;}
|
|
||||||
.event-card .txt-box .ab_cont { padding-top: 10px;}
|
|
||||||
.ab_cont .cost { font-size: 13px; font-weight: 400; color: #7D7971;}
|
|
||||||
del { text-decoration: line-through;}
|
|
||||||
.ab_cont .discount { display: block; font-size: 1rem;}
|
|
||||||
.ab_cont .discount .txt_num { font-size: 1.6em; font-weight: 600; color: #9F2A2A;}
|
|
||||||
.event-card .txt-box .tit-txt:After { content: ''; position: absolute; top: -49px; left: 0; width: 18px; height: 35px; background: center / contain url(https://www.toxnfill2.com/imges/ico-toxnfill-g.png) no-repeat;}
|
|
||||||
.event-card-list .event-card:after { content: ''; position: absolute; bottom: 9px; right: 0; width: 58px; height: 15px; background: center / contain url(https://www.toxnfill2.com/imges/long-arrow-right-g.png) no-repeat;}
|
|
||||||
.add-ticket-btn {
|
|
||||||
font-size: 1.2rem;
|
|
||||||
font-weight: 400;
|
|
||||||
letter-spacing: -0.03em;
|
|
||||||
padding: .35rem 1rem;
|
|
||||||
border: 1px solid #ced4da;
|
|
||||||
border-radius: 50em;
|
|
||||||
transition: 0.2s;
|
|
||||||
background:white;
|
|
||||||
}
|
}
|
||||||
.right { float: right;}
|
|
||||||
.left { float: left;}
|
/* 전체 기본 스타일 */
|
||||||
.card_otxt {
|
html,
|
||||||
position: relative;
|
body {
|
||||||
|
height: 100vh;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
font-family: 'Pretendard', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', sans-serif;
|
||||||
|
background: #f8f9fa;
|
||||||
|
color: #1a1a1a;
|
||||||
|
overflow-x: hidden;
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 메인 컨테이너 */
|
||||||
|
.container {
|
||||||
|
max-width: 1280px;
|
||||||
|
width: 100%;
|
||||||
|
margin: 0 auto;
|
||||||
|
min-height: calc(100vh - 300px);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 상단 헤더 영역 */
|
||||||
|
.header {
|
||||||
|
background: white;
|
||||||
|
border-radius: 16px;
|
||||||
|
box-shadow: 0 2px 16px rgba(0, 0, 0, 0.06);
|
||||||
|
padding: 1rem 2rem;
|
||||||
|
border-bottom: 3px solid #C60B24;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-title {
|
||||||
|
font-size: clamp(1.5rem, 3vw, 1.875rem);
|
||||||
|
font-weight: 700;
|
||||||
|
color: #1a1a1a;
|
||||||
|
margin: 0;
|
||||||
|
letter-spacing: -0.025em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 하단 콘텐츠 영역 (사이드바 + 메인) */
|
||||||
|
.content-wrapper {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
gap: 1.5rem;
|
||||||
|
min-height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 좌측 사이드바 */
|
||||||
|
.sidebar {
|
||||||
|
width: 240px;
|
||||||
|
min-width: 220px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
background: white;
|
||||||
|
border-radius: 16px;
|
||||||
|
box-shadow: 0 2px 16px rgba(0, 0, 0, 0.06);
|
||||||
|
height: fit-content;
|
||||||
|
max-height: 100%;
|
||||||
|
overflow-y: auto;
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-header {
|
||||||
|
padding: 1.25rem 1.5rem;
|
||||||
|
font-size: 1.125rem;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #C60B24;
|
||||||
|
border-bottom: 1px solid #e9ecef;
|
||||||
|
}
|
||||||
|
|
||||||
|
.category-list {
|
||||||
|
list-style: none;
|
||||||
|
padding: 1rem;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.category-item {
|
||||||
|
margin-bottom: 0.375rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.category-link {
|
||||||
display: block;
|
display: block;
|
||||||
border-radius: 1rem;
|
width: 100%;
|
||||||
|
padding: 0.75rem 1rem;
|
||||||
|
font-size: 0.95rem;
|
||||||
|
color: #6b7280;
|
||||||
|
text-decoration: none;
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
border-radius: 10px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.category-link:hover {
|
||||||
|
background: #f9fafb;
|
||||||
|
color: #C60B24;
|
||||||
|
transform: translateX(2px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.category-link.active {
|
||||||
|
background: rgba(198, 11, 36, 0.08);
|
||||||
|
color: #C60B24;
|
||||||
|
font-weight: 600;
|
||||||
|
border-left: 4px solid #C60B24;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 메인 콘텐츠 영역 */
|
||||||
|
.main-content {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 이벤트 리스트 */
|
||||||
|
.event-list {
|
||||||
|
flex: 1;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding-right: 0.5rem;
|
||||||
|
min-height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.event-grid {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 1.25rem;
|
||||||
|
padding-bottom: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 이벤트 카드 */
|
||||||
|
.event-card {
|
||||||
|
display: flex;
|
||||||
|
background: white;
|
||||||
|
border-radius: 16px;
|
||||||
|
box-shadow: 0 2px 16px rgba(0, 0, 0, 0.06);
|
||||||
|
overflow: hidden;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
border: 1px solid #f1f5f9;
|
||||||
|
min-height: 160px;
|
||||||
|
cursor: pointer;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.event-card:hover {
|
||||||
|
transform: translateY(-4px);
|
||||||
|
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.12);
|
||||||
|
border-color: #C60B24;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 지난 이벤트 스타일 */
|
||||||
|
.event-card.expired {
|
||||||
|
opacity: 0.6;
|
||||||
|
filter: grayscale(30%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.event-card.expired:hover {
|
||||||
|
transform: none;
|
||||||
|
box-shadow: 0 2px 16px rgba(0, 0, 0, 0.06);
|
||||||
|
border-color: #9ca3af;
|
||||||
|
}
|
||||||
|
|
||||||
|
.expired-badge {
|
||||||
|
position: absolute;
|
||||||
|
top: 12px;
|
||||||
|
right: 12px;
|
||||||
|
background: rgba(107, 114, 128, 0.9);
|
||||||
|
color: #fff;
|
||||||
|
padding: 4px 12px;
|
||||||
|
border-radius: 20px;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
font-weight: 600;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.event-img {
|
||||||
|
width: 340px;
|
||||||
|
min-width: 280px;
|
||||||
|
background: #f3f4f6;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.event-img img {
|
||||||
|
width: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.event-info {
|
||||||
|
flex: 1;
|
||||||
|
padding: 1.5rem;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: space-between;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.event-title {
|
||||||
|
font-size: 1.25rem;
|
||||||
|
font-weight: 700;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
color: #1a1a1a;
|
||||||
|
letter-spacing: -0.025em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.event-desc {
|
||||||
|
color: #6b7280;
|
||||||
|
font-size: 0.9375rem;
|
||||||
|
margin-bottom: 0.75rem;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.event-meta {
|
||||||
|
font-size: 0.875rem;
|
||||||
|
color: #9ca3af;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.event-date {
|
||||||
|
font-size: 0.85rem;
|
||||||
|
color: #9ca3af;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.event-price {
|
||||||
|
font-size: 1.125rem;
|
||||||
|
color: #C60B24;
|
||||||
|
font-weight: 700;
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 로딩 및 에러 메시지 */
|
||||||
|
.loading {
|
||||||
|
text-align: center;
|
||||||
|
padding: 2rem;
|
||||||
|
color: #6b7280;
|
||||||
|
font-size: 0.9375rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-message {
|
||||||
|
text-align: center;
|
||||||
|
padding: 2rem;
|
||||||
|
color: #dc2626;
|
||||||
|
font-size: 0.9375rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 레이어 팝업 */
|
||||||
|
.popup-overlay {
|
||||||
|
display: none;
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background: rgba(0, 0, 0, 0.5);
|
||||||
|
z-index: 9999;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popup-overlay.active {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popup-content {
|
||||||
|
background: white;
|
||||||
|
border-radius: 16px;
|
||||||
|
padding: 2rem 2.5rem;
|
||||||
|
text-align: center;
|
||||||
|
box-shadow: 0 8px 40px rgba(0, 0, 0, 0.2);
|
||||||
|
max-width: 400px;
|
||||||
|
width: 90%;
|
||||||
|
animation: popupIn 0.25s ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes popupIn {
|
||||||
|
from {
|
||||||
|
transform: scale(0.9);
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
to {
|
||||||
|
transform: scale(1);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.popup-icon {
|
||||||
|
font-size: 3rem;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popup-title {
|
||||||
|
font-size: 1.25rem;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #1a1a1a;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popup-message {
|
||||||
|
font-size: 0.95rem;
|
||||||
|
color: #6b7280;
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popup-close-btn {
|
||||||
|
background: #C60B24;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 0.75rem 2rem;
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: 600;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popup-close-btn:hover {
|
||||||
|
background: #a5091e;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 스크롤바 커스터마이징 */
|
||||||
|
.event-list::-webkit-scrollbar,
|
||||||
|
.sidebar::-webkit-scrollbar {
|
||||||
|
width: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.event-list::-webkit-scrollbar-track,
|
||||||
|
.sidebar::-webkit-scrollbar-track {
|
||||||
|
background: #f8fafc;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.event-list::-webkit-scrollbar-thumb,
|
||||||
|
.sidebar::-webkit-scrollbar-thumb {
|
||||||
|
background: #cbd5e1;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.event-list::-webkit-scrollbar-thumb:hover,
|
||||||
|
.sidebar::-webkit-scrollbar-thumb:hover {
|
||||||
|
background: #C60B24;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 반응형 디자인 - 태블릿 */
|
||||||
|
@media (max-width: 1024px) {
|
||||||
|
.container {
|
||||||
|
padding: 1rem;
|
||||||
|
gap: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-wrapper {
|
||||||
|
gap: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar {
|
||||||
|
width: 220px;
|
||||||
|
min-width: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.event-img {
|
||||||
|
width: 220px;
|
||||||
|
min-width: 220px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.event-img img {
|
||||||
|
height: 140px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
padding: 1.25rem 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-title {
|
||||||
|
font-size: clamp(1.375rem, 2.8vw, 1.75rem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 반응형 디자인 - 모바일 */
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.container {
|
||||||
|
flex-direction: column;
|
||||||
|
padding: 1rem;
|
||||||
|
gap: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-wrapper {
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar {
|
||||||
|
width: 100%;
|
||||||
|
position: static;
|
||||||
|
max-height: none;
|
||||||
|
order: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.category-list {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
|
||||||
|
gap: 0.5rem;
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
}
|
}
|
||||||
.border {
|
|
||||||
border: 1px solid #ddd;
|
|
||||||
}
|
|
||||||
.__card_otxt {
|
|
||||||
height: 95px;
|
|
||||||
}
|
|
||||||
.row>.col2 {
|
|
||||||
width: 50%;
|
|
||||||
margin-bottom: 2rem;
|
|
||||||
}
|
|
||||||
.row.row_padding>.col2, .row.row_padding>.col3, .row.row_padding>.col4, .row.row_padding>.col5 {
|
|
||||||
padding-right: 1rem;
|
|
||||||
padding-left: 1rem;
|
|
||||||
}
|
|
||||||
.row.row_padding {
|
|
||||||
margin-left: -1rem;
|
|
||||||
margin-right: -1rem;
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
}
|
|
||||||
.border-b {
|
|
||||||
border-bottom: 1px solid #ddd;
|
|
||||||
height:5%;
|
|
||||||
}
|
|
||||||
.txt_num {
|
|
||||||
font-family: 'Campton', Sans-serif;
|
|
||||||
font-weight: 600;
|
|
||||||
color: #A73439;
|
|
||||||
}
|
|
||||||
.card_otxt .ab_cont {
|
|
||||||
position: absolute;
|
|
||||||
right: 1rem;
|
|
||||||
top: 3.4rem;
|
|
||||||
width: 8.5em;
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
.card_otxt .fix_cont {
|
|
||||||
padding-right: 11.5rem;
|
|
||||||
}
|
|
||||||
.card_otxt .fix_cont p {
|
|
||||||
margin-bottom: 0;
|
|
||||||
word-break: keep-all;
|
|
||||||
}
|
|
||||||
.mb3{margin-bottom: 3rem;}
|
|
||||||
.mt70{margin-top: 70%;}
|
|
||||||
|
|
||||||
|
.category-link {
|
||||||
/* 반응형 - 모바일 */
|
text-align: center;
|
||||||
@media only screen and (max-width:768px){
|
padding: 0.75rem 0.5rem;
|
||||||
/* main_img */
|
font-size: 0.875rem;
|
||||||
.project_wrap .same main .content5 { padding-bottom:0; }
|
}
|
||||||
.project_wrap .same main .main_img .text_box > div { width:100%; }
|
|
||||||
.project_wrap .same main .main_img .text_box .right_text_box { display:none; }
|
.main-content {
|
||||||
.project_wrap .same main .main_img .text_box .left_text_box p br { display:none; }
|
order: 2;
|
||||||
.project_wrap .same main .main_img .text_box .left_text_box p span { color:#000; }
|
}
|
||||||
.project_wrap .same main {width: 100%;}
|
|
||||||
|
.event-list {
|
||||||
|
overflow-y: visible;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.event-card {
|
||||||
|
flex-direction: column;
|
||||||
|
min-height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.event-img {
|
||||||
|
width: 100%;
|
||||||
|
min-width: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.event-img img {
|
||||||
|
height: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.event-info {
|
||||||
|
padding: 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
padding: 1rem 1.5rem;
|
||||||
|
border-radius: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-title {
|
||||||
|
font-size: clamp(1.25rem, 2.5vw, 1.5rem);
|
||||||
|
}
|
||||||
|
|
||||||
|
.event-title {
|
||||||
|
font-size: 1.125rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.event-price {
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 작은 모바일 */
|
||||||
|
@media (max-width: 480px) {
|
||||||
|
.container {
|
||||||
|
padding: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
padding: 0.875rem 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-title {
|
||||||
|
font-size: clamp(1.125rem, 2.2vw, 1.375rem);
|
||||||
|
}
|
||||||
|
|
||||||
|
.event-info {
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.event-title {
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.event-desc {
|
||||||
|
font-size: 0.875rem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,248 @@
|
|||||||
|
* {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
html,
|
||||||
|
body {
|
||||||
|
height: 100vh;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
font-family: 'Pretendard', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
||||||
|
background: #f8f9fa;
|
||||||
|
color: #1a1a1a;
|
||||||
|
overflow-x: hidden;
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
max-width: 900px;
|
||||||
|
width: 100%;
|
||||||
|
margin: 0 auto;
|
||||||
|
min-height: calc(100vh - 300px);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.breadcrumb {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
color: #9ca3af;
|
||||||
|
padding: 0.5rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.breadcrumb a {
|
||||||
|
color: #6b7280;
|
||||||
|
text-decoration: none;
|
||||||
|
transition: color 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.breadcrumb a:hover {
|
||||||
|
color: #C60B24;
|
||||||
|
}
|
||||||
|
|
||||||
|
.review-article {
|
||||||
|
background: white;
|
||||||
|
border-radius: 16px;
|
||||||
|
box-shadow: 0 2px 16px rgba(0, 0, 0, 0.06);
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.review-header {
|
||||||
|
padding: 2rem 2rem 1.5rem;
|
||||||
|
border-bottom: 1px solid #f1f5f9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.review-title {
|
||||||
|
font-size: clamp(1.375rem, 3vw, 1.75rem);
|
||||||
|
font-weight: 700;
|
||||||
|
color: #1a1a1a;
|
||||||
|
margin: 0 0 1rem;
|
||||||
|
letter-spacing: -0.025em;
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.review-meta {
|
||||||
|
display: flex;
|
||||||
|
gap: 1.5rem;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
color: #9ca3af;
|
||||||
|
margin-bottom: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.review-tags {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.review-tag {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 0.25rem 0.75rem;
|
||||||
|
background: rgba(198, 11, 36, 0.08);
|
||||||
|
color: #C60B24;
|
||||||
|
border-radius: 20px;
|
||||||
|
font-size: 0.8125rem;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.review-content {
|
||||||
|
padding: 2rem;
|
||||||
|
min-height: 300px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.review-content img {
|
||||||
|
max-width: 100%;
|
||||||
|
height: auto;
|
||||||
|
border-radius: 8px;
|
||||||
|
margin: 0.5rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.review-content p {
|
||||||
|
margin: 0 0 0.75rem;
|
||||||
|
line-height: 1.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.review-content h1,
|
||||||
|
.review-content h2,
|
||||||
|
.review-content h3 {
|
||||||
|
margin: 1.5rem 0 0.75rem;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.review-content blockquote {
|
||||||
|
border-left: 4px solid #C60B24;
|
||||||
|
padding: 0.75rem 1rem;
|
||||||
|
margin: 1rem 0;
|
||||||
|
background: #fafafa;
|
||||||
|
border-radius: 0 8px 8px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.review-content ul,
|
||||||
|
.review-content ol {
|
||||||
|
padding-left: 1.5rem;
|
||||||
|
margin: 0.5rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.review-content li {
|
||||||
|
margin: 0.25rem 0;
|
||||||
|
list-style: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ql-editor .ql-align-center {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ql-editor .ql-align-right {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ql-editor .ql-align-justify {
|
||||||
|
text-align: justify;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ql-editor .ql-indent-1 {
|
||||||
|
padding-left: 3em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ql-editor .ql-indent-2 {
|
||||||
|
padding-left: 6em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ql-editor .ql-indent-3 {
|
||||||
|
padding-left: 9em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ql-editor .ql-size-small {
|
||||||
|
font-size: 0.75em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ql-editor .ql-size-large {
|
||||||
|
font-size: 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ql-editor .ql-size-huge {
|
||||||
|
font-size: 2.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ql-editor .ql-font-serif {
|
||||||
|
font-family: Georgia, 'Times New Roman', serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ql-editor .ql-font-monospace {
|
||||||
|
font-family: 'Monaco', 'Courier New', monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-area {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
padding-bottom: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-list {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0.75rem 2.5rem;
|
||||||
|
background: white;
|
||||||
|
color: #1a1a1a;
|
||||||
|
border: 1px solid #e5e7eb;
|
||||||
|
border-radius: 10px;
|
||||||
|
font-size: 0.9375rem;
|
||||||
|
font-weight: 600;
|
||||||
|
text-decoration: none;
|
||||||
|
transition: all 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-list:hover {
|
||||||
|
border-color: #C60B24;
|
||||||
|
color: #C60B24;
|
||||||
|
transform: translateY(-2px);
|
||||||
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading {
|
||||||
|
text-align: center;
|
||||||
|
padding: 3rem;
|
||||||
|
color: #6b7280;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.container {
|
||||||
|
padding: 1rem;
|
||||||
|
gap: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.review-header {
|
||||||
|
padding: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.review-content {
|
||||||
|
padding: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.review-title {
|
||||||
|
font-size: 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.review-meta {
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.25rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 480px) {
|
||||||
|
.container {
|
||||||
|
padding: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.review-header {
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.review-content {
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,399 @@
|
|||||||
|
* {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
html,
|
||||||
|
body {
|
||||||
|
height: 100vh;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
font-family: 'Pretendard', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
||||||
|
background: #f8f9fa;
|
||||||
|
color: #1a1a1a;
|
||||||
|
overflow-x: hidden;
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
max-width: 1280px;
|
||||||
|
width: 100%;
|
||||||
|
margin: 0 auto;
|
||||||
|
min-height: calc(100vh - 300px);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
background: white;
|
||||||
|
border-radius: 16px;
|
||||||
|
box-shadow: 0 2px 16px rgba(0, 0, 0, 0.06);
|
||||||
|
padding: 1.5rem 2rem;
|
||||||
|
border-bottom: 3px solid #C60B24;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-title {
|
||||||
|
font-size: clamp(1.5rem, 3vw, 1.875rem);
|
||||||
|
font-weight: 700;
|
||||||
|
color: #1a1a1a;
|
||||||
|
margin: 0;
|
||||||
|
letter-spacing: -0.025em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-subtitle {
|
||||||
|
font-size: 0.95rem;
|
||||||
|
color: #6b7280;
|
||||||
|
margin: 0.25rem 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-area {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-box {
|
||||||
|
display: flex;
|
||||||
|
gap: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-box input {
|
||||||
|
width: 280px;
|
||||||
|
padding: 0.625rem 1rem;
|
||||||
|
border: 1px solid #e5e7eb;
|
||||||
|
border-radius: 10px;
|
||||||
|
font-size: 0.9375rem;
|
||||||
|
outline: none;
|
||||||
|
transition: border-color 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-box input:focus {
|
||||||
|
border-color: #C60B24;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-btn {
|
||||||
|
padding: 0.625rem 1.25rem;
|
||||||
|
background: #C60B24;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
border-radius: 10px;
|
||||||
|
font-size: 0.9375rem;
|
||||||
|
font-weight: 600;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-btn:hover {
|
||||||
|
background: #a5091e;
|
||||||
|
}
|
||||||
|
|
||||||
|
.review-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(360px, 1fr));
|
||||||
|
gap: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.review-card {
|
||||||
|
background: white;
|
||||||
|
border-radius: 16px;
|
||||||
|
box-shadow: 0 2px 16px rgba(0, 0, 0, 0.06);
|
||||||
|
overflow: hidden;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
border: 1px solid #f1f5f9;
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.review-card:hover {
|
||||||
|
transform: translateY(-4px);
|
||||||
|
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.12);
|
||||||
|
border-color: #C60B24;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== 이미지 슬라이더 ===== */
|
||||||
|
.review-slider {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
aspect-ratio: 4 / 3;
|
||||||
|
overflow: hidden;
|
||||||
|
background: #f1f5f9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.review-slider-track {
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
transition: transform 0.4s cubic-bezier(0.25, 0.46, 0.45, 0.94);
|
||||||
|
}
|
||||||
|
|
||||||
|
.review-slider-track img {
|
||||||
|
min-width: 100%;
|
||||||
|
max-width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slider-arrow {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
background: rgba(0, 0, 0, 0.45);
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
border-radius: 50%;
|
||||||
|
font-size: 14px;
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.25s;
|
||||||
|
z-index: 2;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.review-slider:hover .slider-arrow {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slider-arrow.prev {
|
||||||
|
left: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slider-arrow.next {
|
||||||
|
right: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slider-arrow:hover {
|
||||||
|
background: rgba(0, 0, 0, 0.7);
|
||||||
|
}
|
||||||
|
|
||||||
|
.slider-dots {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 8px;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
display: flex;
|
||||||
|
gap: 5px;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slider-dot {
|
||||||
|
width: 7px;
|
||||||
|
height: 7px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: rgba(255, 255, 255, 0.5);
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 0;
|
||||||
|
transition: all 0.25s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slider-dot.active {
|
||||||
|
background: white;
|
||||||
|
transform: scale(1.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.slider-count {
|
||||||
|
position: absolute;
|
||||||
|
top: 10px;
|
||||||
|
right: 10px;
|
||||||
|
background: rgba(0, 0, 0, 0.55);
|
||||||
|
color: white;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
padding: 2px 8px;
|
||||||
|
border-radius: 12px;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.review-no-image {
|
||||||
|
width: 100%;
|
||||||
|
aspect-ratio: 4 / 3;
|
||||||
|
background: linear-gradient(135deg, #f1f5f9 0%, #e2e8f0 100%);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 2.5rem;
|
||||||
|
color: #cbd5e1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.review-card-body {
|
||||||
|
padding: 1.25rem 1.5rem 1.5rem;
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.review-card-title {
|
||||||
|
font-size: 1.0625rem;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #1a1a1a;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
letter-spacing: -0.025em;
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-line-clamp: 2;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.review-card-summary {
|
||||||
|
color: #6b7280;
|
||||||
|
font-size: 0.8125rem;
|
||||||
|
line-height: 1.6;
|
||||||
|
flex: 1;
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-line-clamp: 2;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
overflow: hidden;
|
||||||
|
margin-bottom: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.review-card-tags {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 0.375rem;
|
||||||
|
margin-bottom: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.review-tag {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 0.2rem 0.5rem;
|
||||||
|
background: rgba(198, 11, 36, 0.08);
|
||||||
|
color: #C60B24;
|
||||||
|
border-radius: 20px;
|
||||||
|
font-size: 0.6875rem;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.review-card-footer {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 0.8125rem;
|
||||||
|
color: #9ca3af;
|
||||||
|
}
|
||||||
|
|
||||||
|
.review-card-footer .views {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-area {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 0.375rem;
|
||||||
|
padding: 1rem 0 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-btn {
|
||||||
|
width: 36px;
|
||||||
|
height: 36px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
border: 1px solid #e5e7eb;
|
||||||
|
background: white;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
color: #6b7280;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-btn:hover {
|
||||||
|
border-color: #C60B24;
|
||||||
|
color: #C60B24;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-btn.active {
|
||||||
|
background: #C60B24;
|
||||||
|
color: white;
|
||||||
|
border-color: #C60B24;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-btn.disabled {
|
||||||
|
opacity: 0.4;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading {
|
||||||
|
text-align: center;
|
||||||
|
padding: 3rem;
|
||||||
|
color: #6b7280;
|
||||||
|
font-size: 0.9375rem;
|
||||||
|
grid-column: 1 / -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-state {
|
||||||
|
text-align: center;
|
||||||
|
padding: 4rem 2rem;
|
||||||
|
grid-column: 1 / -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-state .icon {
|
||||||
|
font-size: 3rem;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-state .message {
|
||||||
|
font-size: 1.125rem;
|
||||||
|
color: #6b7280;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.container {
|
||||||
|
padding: 1rem;
|
||||||
|
gap: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
padding: 1rem 1.5rem;
|
||||||
|
border-radius: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-title {
|
||||||
|
font-size: clamp(1.25rem, 2.5vw, 1.5rem);
|
||||||
|
}
|
||||||
|
|
||||||
|
.review-grid {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
gap: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-area {
|
||||||
|
justify-content: stretch;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-box {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-box input {
|
||||||
|
flex: 1;
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slider-arrow {
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 480px) {
|
||||||
|
.container {
|
||||||
|
padding: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
padding: 0.875rem 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.review-card-body {
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
src/main/resources/static/image/equip/20251014/써마지.jpg
Normal file
|
After Width: | Height: | Size: 99 KiB |
BIN
src/main/resources/static/image/equip/20251014/울쎄라.jpg
Normal file
|
After Width: | Height: | Size: 92 KiB |
BIN
src/main/resources/static/image/equip/20251014/줄기세포.jpg
Normal file
|
After Width: | Height: | Size: 89 KiB |
BIN
src/main/resources/static/image/equip/20251014/튠페이스.jpg
Normal file
|
After Width: | Height: | Size: 104 KiB |
BIN
src/main/resources/static/image/equip/20251014/티타늄.jpg
Normal file
|
After Width: | Height: | Size: 100 KiB |
BIN
src/main/resources/static/image/equip/20260313/써마지FLX.jpg
Normal file
|
After Width: | Height: | Size: 115 KiB |
BIN
src/main/resources/static/image/equip/20260313/온다리프팅(Face).jpg
Normal file
|
After Width: | Height: | Size: 163 KiB |
BIN
src/main/resources/static/image/equip/20260313/울쎄라.jpg
Normal file
|
After Width: | Height: | Size: 104 KiB |
BIN
src/main/resources/static/image/equip/20260313/튠페이스.jpg
Normal file
|
After Width: | Height: | Size: 124 KiB |
BIN
src/main/resources/static/image/equip/20260313/티타늄리프팅(Face).jpg
Normal file
|
After Width: | Height: | Size: 124 KiB |
BIN
src/main/resources/static/image/equip/온다리프팅.jpg
Normal file
|
After Width: | Height: | Size: 44 KiB |
BIN
src/main/resources/static/image/quick_menu/event.png
Normal file
|
After Width: | Height: | Size: 6.8 KiB |
BIN
src/main/resources/static/image/quick_menu/review.png
Normal file
|
After Width: | Height: | Size: 8.1 KiB |
BIN
src/main/resources/static/image/signature/20251024/레이저리프팅.jpg
Normal file
|
After Width: | Height: | Size: 255 KiB |
|
After Width: | Height: | Size: 250 KiB |
BIN
src/main/resources/static/image/signature/20251024/스컬트라.jpg
Normal file
|
After Width: | Height: | Size: 234 KiB |
BIN
src/main/resources/static/image/signature/20251024/스킨부스터.jpg
Normal file
|
After Width: | Height: | Size: 271 KiB |
BIN
src/main/resources/static/image/signature/20251024/필러.jpg
Normal file
|
After Width: | Height: | Size: 221 KiB |
@@ -54,7 +54,7 @@ const cont1Urls = [
|
|||||||
// 필요시 추가
|
// 필요시 추가
|
||||||
];
|
];
|
||||||
|
|
||||||
const bullet1 = ['레이저리프팅','보톡스','스킨부스터','제모', '필러']
|
const bullet1 = ['레이저리프팅', '쉬다주사(Face)', '스컬트라', '스킨부스터', '필러']
|
||||||
|
|
||||||
const useCont1Loop = bullet1.length > 5; // slidesPerView(1.3)보다 많을 때만 loop
|
const useCont1Loop = bullet1.length > 5; // slidesPerView(1.3)보다 많을 때만 loop
|
||||||
const cont1Swiper = new Swiper('.cont1_swiper', {
|
const cont1Swiper = new Swiper('.cont1_swiper', {
|
||||||
@@ -99,14 +99,14 @@ const cont1Swiper = new Swiper('.cont1_swiper', {
|
|||||||
* content2 스와이퍼
|
* content2 스와이퍼
|
||||||
************************************************/
|
************************************************/
|
||||||
const cont2Urls = [
|
const cont2Urls = [
|
||||||
'https://petit.madeu.co.kr/webservice/selectServiceIntro.do?categoryNo=4' // 첫 번째 슬라이드 URL
|
'https://petit.madeu.co.kr/webservice/selectServiceDetailIntro.do?categoryDivCd=03&categoryNo=4&postNo=8' // 첫 번째 슬라이드 URL
|
||||||
,'https://petit.madeu.co.kr/webservice/selectServiceIntro.do?categoryNo=4' // 두 번째 슬라이드 URL
|
, 'https://petit.madeu.co.kr/webservice/selectServiceDetailIntro.do?categoryDivCd=03&categoryNo=4&postNo=2' // 두 번째 슬라이드 URL
|
||||||
,'https://petit.madeu.co.kr/webservice/selectServiceIntro.do?categoryNo=4' // 세 번째 슬라이드 URL
|
, 'https://petit.madeu.co.kr/webservice/selectServiceDetailIntro.do?categoryDivCd=03&categoryNo=4&postNo=10' // 세 번째 슬라이드 URL
|
||||||
,'https://petit.madeu.co.kr/webservice/selectServiceIntro.do?categoryNo=4' // 네 번째 슬라이드 URL
|
, 'https://petit.madeu.co.kr/webservice/selectServiceDetailIntro.do?categoryDivCd=03&categoryNo=4&postNo=3' // 네 번째 슬라이드 URL
|
||||||
,'https://petit.madeu.co.kr/webservice/selectServiceIntro.do?categoryNo=4' // 다섯 번째 슬라이드 URL
|
, 'https://petit.madeu.co.kr/webservice/selectServiceDetailIntro.do?categoryDivCd=03&categoryNo=4&postNo=4' // 다섯 번째 슬라이드 URL
|
||||||
];
|
];
|
||||||
|
|
||||||
const bullet2 = ['써마지','울세라','줄기세포', '튠페이스', '티타늄리프팅']
|
const bullet2 = ['써마지FLX', '울쎄라', '온다리프팅', '티타늄리프팅', '튠페이스']
|
||||||
|
|
||||||
const useCont2Loop = bullet2.length > 5; // slidesPerView(1.3)보다 많을 때만 loop
|
const useCont2Loop = bullet2.length > 5; // slidesPerView(1.3)보다 많을 때만 loop
|
||||||
const cont2Swiper = new Swiper('.cont2_swiper', {
|
const cont2Swiper = new Swiper('.cont2_swiper', {
|
||||||
|
|||||||
@@ -189,12 +189,13 @@ function fn_RenderServices(services) {
|
|||||||
|
|
||||||
let servicesHtml = '';
|
let servicesHtml = '';
|
||||||
services.forEach(function(service) {
|
services.forEach(function(service) {
|
||||||
|
|
||||||
servicesHtml += `
|
servicesHtml += `
|
||||||
<div class="service-card" onclick="fn_GoToDetail('${service.CATEGORY_DIV_CD}', '${service.CATEGORY_NO}', '${service.POST_NO}')" style="cursor: pointer;">
|
<div class="service-card" onclick="fn_GoToDetail('${service.CATEGORY_DIV_CD}', '${service.CATEGORY_NO}', '${service.POST_NO}')" style="cursor: pointer;">
|
||||||
<div class="service-title">${service.SERVICE_NM || service.TITLE || '서비스명 없음'}</div>
|
<div class="service-title">${service.SERVICE_NM || service.TITLE || '서비스명 없음'}</div>
|
||||||
<div class="service-description">${service.SERVICE_DESC || service.CONTENT || '설명 없음'}</div>
|
<div class="service-description">${service.SERVICE_DESC || service.CONTENT || '설명 없음'}</div>
|
||||||
<div class="service-price"><span class="cancel-price">${fn_FormatPrice(service.PRICE)}</span> ${fn_FormatPrice(service.DISCOUNT_PRICE)}</div>
|
<div class="service-price">
|
||||||
|
${service.PRICE !== service.DISCOUNT_PRICE ? `<span class="cancel-price">${fn_FormatPrice(service.PRICE)}</span> ` : ''}${fn_FormatPrice(service.DISCOUNT_PRICE)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,19 +1,16 @@
|
|||||||
/************************************************
|
// 전역 변수
|
||||||
* 초기화
|
let procedureChoices;
|
||||||
************************************************/
|
let priceList = [];
|
||||||
function fn_init() {
|
const totalEl = document.getElementById('total');
|
||||||
fn_SelectDetail(category_div_cd, category_no, post_no);
|
const reserveBtn = document.getElementById('reserve-btn');
|
||||||
|
|
||||||
$("#btn_makeReservation").on("click", function(){
|
// 초기화
|
||||||
fn_moveReservation(category_div_cd, category_no, post_no);
|
fn_SelectDetail(category_div_cd, category_no, post_no);
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* 카테고리 목록 가져오기
|
* 카테고리 목록 가져오기
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
function fn_SelectDetail(category_div_cd, category_no, post_no) {
|
function fn_SelectDetail(category_div_cd, category_no, post_no) {
|
||||||
|
|
||||||
let formData = new FormData();
|
let formData = new FormData();
|
||||||
formData.append('CATEGORY_DIV_CD', category_div_cd);
|
formData.append('CATEGORY_DIV_CD', category_div_cd);
|
||||||
formData.append('CATEGORY_NO', category_no);
|
formData.append('CATEGORY_NO', category_no);
|
||||||
@@ -30,207 +27,288 @@ function fn_SelectDetail(category_div_cd, category_no, post_no){
|
|||||||
success: function (data) {
|
success: function (data) {
|
||||||
if (data.msgCode == '0') {
|
if (data.msgCode == '0') {
|
||||||
// 화면 데이터 변경
|
// 화면 데이터 변경
|
||||||
$('#category_nm').text(data.rows.CATEGORY_NM);
|
|
||||||
$('#title').text(data.rows.TITLE);
|
$('#title').text(data.rows.TITLE);
|
||||||
$('#serviceThumb').attr('src', data.rows.THUMBNAIL_PATH);
|
$('#serviceThumb').attr('src', CDN_URL + data.rows.THUMBNAIL_PATH);
|
||||||
$('#main_title').text(data.rows.TITLE);
|
$('#thumbnail-bottom-txt').text(data.rows.THUMBNAIL_BOTTOM_TXT);
|
||||||
$('.thumbnail-bottom-txt').text(data.rows.THUMBNAIL_BOTTOM_TXT);
|
|
||||||
$('#contents').text(data.rows.CONTENT);
|
$('#contents').text(data.rows.CONTENT);
|
||||||
if(data.rows.PRICE == null || data.rows.PRICE == undefined){
|
|
||||||
$('#startprice').text('0');
|
|
||||||
}else{
|
|
||||||
$('#startprice').text(data.rows.PRICE.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","));
|
|
||||||
}
|
|
||||||
$('#hashtag').text(data.rows.HASHTAG);
|
|
||||||
$('#contents_path').text(data.rows.THUMBNAIL_BOTTOM_TXT);
|
|
||||||
$('#contents_path').attr('src', data.rows.CONTENTS_PATH);
|
|
||||||
//시술 목록 데이터 입력
|
|
||||||
let totalCount = data.price.length;
|
|
||||||
if (0 < totalCount) {
|
|
||||||
for (let i = 0; i < data.price.length; i++) {
|
|
||||||
let listHTML = '';
|
|
||||||
listHTML += '<li class="optipon_item sepr_wrap">';
|
|
||||||
listHTML += ' <div class="item_subprice">';
|
|
||||||
listHTML += ' <div class="cs-checkbox">';
|
|
||||||
listHTML += ' <input type="checkbox" class="idxChk" id="checkboxID' + i + '">';
|
|
||||||
listHTML += ' <label class="cs-checkbox-label d-block" for="checkboxID' + i + '">';
|
|
||||||
listHTML += ' <div class="oi-wrap">';
|
|
||||||
listHTML += ' <div class="oi-txt">';
|
|
||||||
listHTML += ' <span class="oi-tit-txt">' + data.price[i].TREATMENT_PROCEDURE_NAME;
|
|
||||||
listHTML += ' </span>';
|
|
||||||
listHTML += ' </div>';
|
|
||||||
listHTML += ' <div class="oi-price">';
|
|
||||||
listHTML += ' <del class="original_price d-block">';
|
|
||||||
listHTML += ' <b>';
|
|
||||||
if(data.price[i].DISCOUNT_PRICE == null || data.price[i].DISCOUNT_PRICE == undefined){
|
|
||||||
if(data.price[i].PRICE == null || data.price[i].PRICE == undefined){
|
|
||||||
listHTML += '0';
|
|
||||||
}else{
|
|
||||||
listHTML += (data.price[i].PRICE).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
|
||||||
}
|
|
||||||
}else{
|
|
||||||
listHTML += (data.price[i].DISCOUNT_PRICE).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
|
||||||
}
|
|
||||||
listHTML += '</b>원';
|
|
||||||
listHTML += ' </del>';
|
|
||||||
listHTML += ' <span class="discount_price">';
|
|
||||||
if(data.price[i].DISCOUNT_PRICE == null || data.price[i].DISCOUNT_PRICE == undefined){
|
|
||||||
if(data.price[i].PRICE == null || data.price[i].PRICE == undefined){
|
|
||||||
listHTML += '0';
|
|
||||||
}else{
|
|
||||||
listHTML += (data.price[i].PRICE).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
|
||||||
}
|
|
||||||
}else{
|
|
||||||
listHTML += (data.price[i].DISCOUNT_PRICE).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
|
||||||
}
|
|
||||||
listHTML += '</span>원';
|
|
||||||
listHTML += ' </div>';
|
|
||||||
listHTML += ' </div>';
|
|
||||||
listHTML += ' </label>';
|
|
||||||
listHTML += ' </div>';
|
|
||||||
listHTML += ' </div>';
|
|
||||||
listHTML += '</li>';
|
|
||||||
$(".option_list").append(listHTML);
|
|
||||||
|
|
||||||
$("#checkboxID" + i).change(function(){
|
if (data.rows.PRICE == null || data.rows.PRICE == undefined) {
|
||||||
if($("#checkboxID" + i).is(":checked")){
|
$('#price').text('0');
|
||||||
let listHTML2 = '';
|
|
||||||
listHTML2 += '<li class="s_item selt_info_wrap" id="liid' + i + '">';
|
|
||||||
listHTML2 += '<input type="hidden" id="procedure_id' + i + '" name="procedure_id" value="'+ data.price[i].MU_TREATMENT_PROCEDURE_ID + '">';
|
|
||||||
listHTML2 += ' <div class="txt-wrap"> ';
|
|
||||||
listHTML2 += ' <span class="selt">' + data.price[i].TREATMENT_PROCEDURE_NAME;
|
|
||||||
listHTML2 += ' </div>';
|
|
||||||
listHTML2 += ' <div class="info">';
|
|
||||||
listHTML2 += ' <span><span class="real_price">';
|
|
||||||
if(data.price[i].DISCOUNT_PRICE == null || data.price[i].DISCOUNT_PRICE == undefined){
|
|
||||||
if(data.price[i].PRICE == null || data.price[i].PRICE == undefined){
|
|
||||||
listHTML2 += '0';
|
|
||||||
} else {
|
} else {
|
||||||
listHTML2 += (data.price[i].PRICE).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
$('#price').text(data.rows.PRICE.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","));
|
||||||
}
|
}
|
||||||
}else{
|
|
||||||
listHTML2 += (data.price[i].DISCOUNT_PRICE).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
// header 동적 변경
|
||||||
}
|
$('#header-category-nm').text(data.rows.CATEGORY_NM);
|
||||||
listHTML2 += '</span>원</span>';
|
$('#header-title').text(data.rows.TITLE);
|
||||||
listHTML2 += ' <button type="button" onclick="fn_nocheck(' + i + ');"><img src="/image/close-btn.png" alt="삭제" width="13px" height="13px"></button>';
|
|
||||||
listHTML2 += ' </div>';
|
// 해시태그 처리
|
||||||
listHTML2 += '</li>';
|
var hashtagHtml = '';
|
||||||
$("#selectEvent1").append(listHTML2);
|
if (data.rows.HASHTAG) {
|
||||||
var price = $("#price_div1").text().replace(/,/g, "");
|
var tags = data.rows.HASHTAG.split('#');
|
||||||
var discount_price = '';
|
tags.forEach(function (tag) {
|
||||||
if(data.price[i].DISCOUNT_PRICE == null || data.price[i].DISCOUNT_PRICE == undefined){
|
var trimmed = tag.trim();
|
||||||
if(data.price[i].PRICE == null || data.price[i].PRICE == undefined){
|
if (trimmed) {
|
||||||
discount_price = 0;
|
hashtagHtml += '<span class="hashtag">#' + trimmed + '</span>';
|
||||||
}else{
|
|
||||||
discount_price = data.price[i].PRICE;
|
|
||||||
}
|
|
||||||
}else{
|
|
||||||
discount_price = data.price[i].DISCOUNT_PRICE;
|
|
||||||
}
|
|
||||||
price = Number(price) + Number(discount_price);
|
|
||||||
$("#price_div1").text(price.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","));
|
|
||||||
}else{
|
|
||||||
fn_deleteList(i);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
$('.hashtag-list').html(hashtagHtml);
|
||||||
|
|
||||||
|
$('#contents_path').attr('src', CDN_URL + data.rows.CONTENTS_PATH);
|
||||||
|
|
||||||
|
// 이벤트 기간 정보 저장
|
||||||
|
window.eventStartDt = data.rows.EVENT_START_DT || '';
|
||||||
|
window.eventEndDt = data.rows.EVENT_END_DT || '';
|
||||||
|
|
||||||
|
// 이벤트 기간 표시
|
||||||
|
if (window.eventStartDt || window.eventEndDt) {
|
||||||
|
const periodEl = document.getElementById('event-period');
|
||||||
|
if (periodEl) {
|
||||||
|
let periodText = '📅 이벤트 기간: ';
|
||||||
|
if (window.eventStartDt && window.eventEndDt) {
|
||||||
|
periodText += window.eventStartDt + ' ~ ' + window.eventEndDt;
|
||||||
|
} else if (window.eventEndDt) {
|
||||||
|
periodText += '~ ' + window.eventEndDt;
|
||||||
} else {
|
} else {
|
||||||
listHTML += '<li>';
|
periodText += window.eventStartDt + ' ~';
|
||||||
listHTML += '</li>';
|
|
||||||
$(".option_list").html(listHTML);
|
|
||||||
}
|
}
|
||||||
|
periodEl.textContent = periodText;
|
||||||
|
periodEl.style.display = 'block';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 시술 목록 데이터 처리
|
||||||
|
updateProcedureOptions(data.price || []);
|
||||||
} else {
|
} else {
|
||||||
modalEvent.danger("조회 오류", data.msgDesc);
|
modalEvent.danger("조회 오류", data.msgDesc);
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
error: function (xhr, status, error) {
|
error: function (xhr, status, error) {
|
||||||
modalEvent.danger("조회 오류", "조회 중 오류가 발생하였습니다. 잠시후 다시시도하십시오.");
|
modalEvent.danger("조회 오류", "조회 중 오류가 발생하였습니다. 잠시후 다시시도하십시오.");
|
||||||
},
|
},
|
||||||
beforeSend: function () {
|
beforeSend: function () {
|
||||||
// 로딩열기
|
|
||||||
$(".loading-image-layer").show();
|
$(".loading-image-layer").show();
|
||||||
},
|
},
|
||||||
complete: function () {
|
complete: function () {
|
||||||
// 로딩닫기
|
|
||||||
$(".loading-image-layer").hide();
|
$(".loading-image-layer").hide();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function fn_nocheck(num){
|
/****************************************************************************
|
||||||
$("#checkboxID" + num).prop("checked",false);
|
* Choices.js 초기화 및 옵션 업데이트
|
||||||
fn_deleteList(num);
|
****************************************************************************/
|
||||||
|
function updateProcedureOptions(data) {
|
||||||
|
priceList = data;
|
||||||
|
|
||||||
|
// 기존 Choices 인스턴스 제거
|
||||||
|
if (procedureChoices) {
|
||||||
|
procedureChoices.destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
function fn_deleteList(num){
|
// 선택 옵션 데이터 생성
|
||||||
|
const choices = data.map(item => {
|
||||||
|
if (!item.MU_TREATMENT_PROCEDURE_ID || !item.TREATMENT_PROCEDURE_NAME) return null;
|
||||||
|
|
||||||
var price = $("#price_div1").text().replace(/,/g, "");
|
const basePrice = (item.PRICE || 0) + (item.VAT || 0);
|
||||||
var discount_price = $("#liid" + num + " > div.info > span > span").text().replace(/,/g, "");
|
const discountPrice = item.DISCOUNT_PRICE;
|
||||||
|
|
||||||
price = Number(price) - Number(discount_price);
|
return {
|
||||||
$("#price_div1").text(price.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","));
|
value: item.MU_TREATMENT_PROCEDURE_ID,
|
||||||
$("#liid" + num).remove();
|
label: item.TREATMENT_PROCEDURE_NAME,
|
||||||
|
customProperties: {
|
||||||
|
name: item.TREATMENT_PROCEDURE_NAME,
|
||||||
|
price: basePrice,
|
||||||
|
discountPrice: discountPrice,
|
||||||
|
originalData: item
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}).filter(Boolean);
|
||||||
|
|
||||||
|
// Choices.js 초기화
|
||||||
|
procedureChoices = new Choices('#procedure-select', {
|
||||||
|
removeItemButton: true,
|
||||||
|
searchEnabled: true,
|
||||||
|
searchPlaceholderValue: '시술명으로 검색...',
|
||||||
|
placeholder: true,
|
||||||
|
placeholderValue: '시술을 선택하세요',
|
||||||
|
maxItemCount: -1,
|
||||||
|
choices: choices,
|
||||||
|
shouldSort: false,
|
||||||
|
searchResultLimit: 10,
|
||||||
|
searchFields: ['label', 'value'],
|
||||||
|
itemSelectText: '',
|
||||||
|
noChoicesText: '선택 가능한 시술이 없습니다',
|
||||||
|
noResultsText: '검색 결과가 없습니다',
|
||||||
|
loadingText: '시술 정보를 불러오는 중...',
|
||||||
|
|
||||||
|
// 템플릿 커스터마이징 - 선택된 항목에 가격 표시 추가
|
||||||
|
callbackOnCreateTemplates: function (template) {
|
||||||
|
return {
|
||||||
|
// 선택된 항목 템플릿 - 가격 정보 포함
|
||||||
|
item: ({ classNames }, data) => {
|
||||||
|
const customProps = data.customProperties || {};
|
||||||
|
const name = customProps.name || data.label;
|
||||||
|
const price = customProps.price || 0;
|
||||||
|
const discountPrice = customProps.discountPrice;
|
||||||
|
|
||||||
|
// 가격 표시 HTML 생성
|
||||||
|
let priceHtml = '';
|
||||||
|
if (discountPrice && discountPrice < price) {
|
||||||
|
priceHtml = `
|
||||||
|
<span class="selected-price-discount">${discountPrice.toLocaleString()}원</span>
|
||||||
|
<span class="selected-price-original">${price.toLocaleString()}원</span>
|
||||||
|
`;
|
||||||
|
} else {
|
||||||
|
priceHtml = `<span class="selected-price">${price.toLocaleString()}원</span>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function fn_moveReservation(category_div, category_no, post_no){
|
return template(`
|
||||||
let pageMoveForm = document.createElement('form');
|
<div class="${classNames.item} ${data.highlighted ? classNames.highlightedState : classNames.itemSelectable}" data-item data-id="${data.id}" data-value="${data.value}">
|
||||||
let obj = document.createElement('input');
|
<span class="selected-item-content">
|
||||||
obj.setAttribute('type', 'hidden');
|
<span class="selected-item-name">${name}</span>
|
||||||
obj.setAttribute('name', 'CATEGORY_DIV_CD');
|
<span class="selected-item-price">${priceHtml}</span>
|
||||||
obj.setAttribute('value', "0"+category_div);
|
</span>
|
||||||
pageMoveForm.appendChild(obj);
|
<button type="button" class="${classNames.button}" aria-label="Remove item: '${data.value}'" data-button>X</button>
|
||||||
|
|
||||||
let obj2 = document.createElement('input');
|
</div>
|
||||||
obj2.setAttribute('type', 'hidden');
|
`);
|
||||||
obj2.setAttribute('name', 'CATEGORY_NO');
|
},
|
||||||
obj2.setAttribute('value', category_no);
|
|
||||||
pageMoveForm.appendChild(obj2);
|
|
||||||
|
|
||||||
let obj3 = document.createElement('input');
|
// 드롭다운 선택 옵션 템플릿
|
||||||
obj3.setAttribute('type', 'hidden');
|
choice: ({ classNames }, data) => {
|
||||||
obj3.setAttribute('name', 'POST_NO');
|
const customProps = data.customProperties || {};
|
||||||
obj3.setAttribute('value', post_no);
|
const name = customProps.name || data.label;
|
||||||
pageMoveForm.appendChild(obj3);
|
const price = customProps.price || 0;
|
||||||
|
const discountPrice = customProps.discountPrice;
|
||||||
|
|
||||||
let obj4 = document.getElementsByName('procedure_id');
|
let priceHtml = '';
|
||||||
var len = obj4.length;
|
if (discountPrice && discountPrice < price) {
|
||||||
if(len == 0){
|
priceHtml = `
|
||||||
alert('시술이 선택되지 않았습니다.');
|
<span class="procedure-price-discount">${discountPrice.toLocaleString()}원</span>
|
||||||
return;
|
<span class="procedure-price-original">${price.toLocaleString()}원</span>
|
||||||
}
|
`;
|
||||||
var value = '';
|
} else {
|
||||||
for(var i = 0; i < len; i++){
|
priceHtml = `<span class="procedure-price">${price.toLocaleString()}원</span>`;
|
||||||
value += obj4[i].getAttribute('value') + '#';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let obj5 = document.createElement('input');
|
return template(`
|
||||||
obj5.setAttribute('type', 'hidden');
|
<div class="${classNames.item} ${classNames.itemChoice} ${data.disabled ? classNames.itemDisabled : classNames.itemSelectable}" data-select-text="" data-choice ${data.disabled ? 'data-choice-disabled aria-disabled="true"' : 'data-choice-selectable'} data-id="${data.id}" data-value="${data.value}">
|
||||||
obj5.setAttribute('name', 'PROCEDURE_ID');
|
<div style="display: flex; justify-content: space-between; width: 100%; align-items: center;">
|
||||||
obj5.setAttribute('value', value);
|
<span>${name}</span>
|
||||||
pageMoveForm.appendChild(obj5);
|
${priceHtml}
|
||||||
|
</div>
|
||||||
pageMoveForm.setAttribute('method', 'post');
|
</div>
|
||||||
pageMoveForm.setAttribute('action', '/webservice/selectMakeReservation.do');
|
`);
|
||||||
document.body.appendChild(pageMoveForm);
|
}
|
||||||
|
};
|
||||||
pageMoveForm.submit();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 버튼 클릭했는지 안했는지 확인 class active */
|
|
||||||
var $selectProcedureDiv = $('.select_procedure_div');
|
|
||||||
$selectProcedureDiv.click(function(e){
|
|
||||||
e.stopPropagation();
|
|
||||||
$selectProcedureDiv.not(this).removeClass('active'); /*remove buttonactive from the others*/
|
|
||||||
$(this).toggleClass('active'); /*toggle current clicked element*/
|
|
||||||
});
|
});
|
||||||
|
|
||||||
$(window).on("click", function(){
|
// 이벤트 리스너 추가
|
||||||
$selectProcedureDiv.removeClass('active');
|
const selectElement = document.getElementById('procedure-select');
|
||||||
})
|
selectElement.addEventListener('change', function (event) {
|
||||||
|
console.log('Selection changed:', event.detail);
|
||||||
|
updateTotalPrice();
|
||||||
|
});
|
||||||
|
|
||||||
//초기화
|
selectElement.addEventListener('addItem', function (event) {
|
||||||
fn_init();
|
console.log('Item added:', event.detail);
|
||||||
|
updateTotalPrice();
|
||||||
|
});
|
||||||
|
|
||||||
|
selectElement.addEventListener('removeItem', function (event) {
|
||||||
|
console.log('Item removed:', event.detail);
|
||||||
|
updateTotalPrice();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* 총 금액 업데이트 - 개선된 버전
|
||||||
|
****************************************************************************/
|
||||||
|
function updateTotalPrice() {
|
||||||
|
if (!procedureChoices) {
|
||||||
|
console.log('procedureChoices not initialized');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const selectedValues = procedureChoices.getValue(true);
|
||||||
|
console.log('Selected values:', selectedValues);
|
||||||
|
|
||||||
|
let total = 0;
|
||||||
|
|
||||||
|
selectedValues.forEach(value => {
|
||||||
|
const item = priceList.find(p => p.MU_TREATMENT_PROCEDURE_ID == value);
|
||||||
|
console.log('Found item for value', value, ':', item);
|
||||||
|
|
||||||
|
if (item) {
|
||||||
|
const basePrice = (item.PRICE || 0) + (item.VAT || 0);
|
||||||
|
const discountPrice = item.DISCOUNT_PRICE;
|
||||||
|
|
||||||
|
// 할인가가 있고 더 저렴하면 할인가 사용, 아니면 기본가격 사용
|
||||||
|
const finalPrice = (discountPrice && discountPrice < basePrice) ? discountPrice : basePrice;
|
||||||
|
total += finalPrice;
|
||||||
|
console.log('Added price:', finalPrice);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log('Total calculated:', total);
|
||||||
|
totalEl.textContent = total.toLocaleString() + '원';
|
||||||
|
reserveBtn.disabled = selectedValues.length === 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* 예약 페이지로 이동
|
||||||
|
****************************************************************************/
|
||||||
|
function fn_moveReservation(category_div, category_no, post_no) {
|
||||||
|
if (!procedureChoices) {
|
||||||
|
alert('시술 선택 기능이 초기화되지 않았습니다.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const selectedValues = procedureChoices.getValue(true);
|
||||||
|
|
||||||
|
if (selectedValues.length === 0) {
|
||||||
|
alert('시술을 선택해주세요.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const form = document.createElement('form');
|
||||||
|
form.method = 'post';
|
||||||
|
form.action = '/webevent/selectMakeReservation.do';
|
||||||
|
|
||||||
|
// 기본 파라미터 추가
|
||||||
|
const params = [
|
||||||
|
{ name: 'CATEGORY_DIV_CD', value: category_div },
|
||||||
|
{ name: 'CATEGORY_NO', value: category_no },
|
||||||
|
{ name: 'POST_NO', value: post_no },
|
||||||
|
{ name: 'EVENT_START_DT', value: window.eventStartDt || '' },
|
||||||
|
{ name: 'EVENT_END_DT', value: window.eventEndDt || '' }
|
||||||
|
];
|
||||||
|
|
||||||
|
params.forEach(param => {
|
||||||
|
const input = document.createElement('input');
|
||||||
|
input.type = 'hidden';
|
||||||
|
input.name = param.name;
|
||||||
|
input.value = param.value;
|
||||||
|
form.appendChild(input);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 선택된 시술 추가
|
||||||
|
selectedValues.forEach(value => {
|
||||||
|
const input = document.createElement('input');
|
||||||
|
input.type = 'hidden';
|
||||||
|
input.name = 'PROCEDURE_ID';
|
||||||
|
input.value = value;
|
||||||
|
form.appendChild(input);
|
||||||
|
});
|
||||||
|
|
||||||
|
document.body.appendChild(form);
|
||||||
|
form.submit();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 예약 버튼 이벤트
|
||||||
|
reserveBtn.addEventListener('click', function () {
|
||||||
|
fn_moveReservation(category_div_cd, category_no, post_no);
|
||||||
|
});
|
||||||
@@ -1,189 +1,216 @@
|
|||||||
/************************************************
|
class EventManager {
|
||||||
* 초기화
|
constructor() {
|
||||||
************************************************/
|
this.events = [];
|
||||||
function fn_init() {
|
this.categories = [];
|
||||||
fn_SelectListCategory();
|
this.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async init() {
|
||||||
|
await this.loadCategories();
|
||||||
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
async apiRequest(url, data) {
|
||||||
* 이벤트 카테고리 목록 가져오기
|
return new Promise((resolve, reject) => {
|
||||||
****************************************************************************/
|
$.ajax({
|
||||||
function fn_SelectListCategory(){
|
url: encodeURI(url),
|
||||||
|
data: data,
|
||||||
|
dataType: 'json',
|
||||||
|
processData: false,
|
||||||
|
contentType: false,
|
||||||
|
type: 'POST',
|
||||||
|
success: resolve,
|
||||||
|
error: reject,
|
||||||
|
beforeSend: () => $(".loading-image-layer").show(),
|
||||||
|
complete: () => $(".loading-image-layer").hide()
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
let formData = new FormData();
|
async loadCategories() {
|
||||||
|
try {
|
||||||
|
const formData = new FormData();
|
||||||
formData.append('bannerType', 'A');
|
formData.append('bannerType', 'A');
|
||||||
|
const data = await this.apiRequest('/webevent/selectListWebEvent.do', formData);
|
||||||
|
|
||||||
$.ajax({
|
if (data.msgCode === '0') {
|
||||||
url: encodeURI('/webevent/selectListWebEvent.do'),
|
this.categories = data.rows;
|
||||||
data: formData,
|
this.renderCategories();
|
||||||
dataType: 'json',
|
if (this.categories.length > 0) {
|
||||||
processData: false,
|
this.loadEvents(this.categories[0].CATEGORY_NO);
|
||||||
contentType: false,
|
|
||||||
type: 'POST',
|
|
||||||
async: true,
|
|
||||||
success: function(data){
|
|
||||||
if(data.msgCode=='0'){
|
|
||||||
|
|
||||||
let totalCount = data.rows.length;
|
|
||||||
|
|
||||||
if (0 < totalCount) {
|
|
||||||
let listHTML = '';
|
|
||||||
|
|
||||||
for (let i = 0; i < data.rows.length; i++) {
|
|
||||||
if(i == 0){
|
|
||||||
listHTML += '<li class="active" id="category_'+data.rows[i].CATEGORY_NO+'">';
|
|
||||||
listHTML += ' <a href="javascript:fn_SelectEventList(' + data.rows[i].CATEGORY_NO + ');">' + data.rows[i].CATEGORY_NM + '</a>';
|
|
||||||
listHTML += '</li>';
|
|
||||||
}else{
|
|
||||||
listHTML += '<li class="nonactive" id="category_'+data.rows[i].CATEGORY_NO+'">';
|
|
||||||
listHTML += ' <a href="javascript:fn_SelectEventList(' + data.rows[i].CATEGORY_NO + ');">' + data.rows[i].CATEGORY_NM + '</a>';
|
|
||||||
listHTML += '</li>';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$("#servicecategory").html(listHTML);
|
|
||||||
fn_SelectEventList(data.rows[0].CATEGORY_NO);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
modalEvent.danger("조회 오류", data.msgDesc);
|
modalEvent.danger("조회 오류", data.msgDesc);
|
||||||
}
|
}
|
||||||
|
} catch (error) {
|
||||||
},
|
modalEvent.danger("조회 오류", "조회 중 오류가 발생하였습니다.");
|
||||||
error : function(xhr, status, error) {
|
|
||||||
modalEvent.danger("조회 오류", "조회 중 오류가 발생하였습니다. 잠시후 다시시도하십시오.");
|
|
||||||
},
|
|
||||||
beforeSend:function(){
|
|
||||||
// 로딩열기
|
|
||||||
$(".loading-image-layer").show();
|
|
||||||
},
|
|
||||||
complete:function(){
|
|
||||||
// 로딩닫기
|
|
||||||
$(".loading-image-layer").hide();
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async loadEvents(categoryNo) {
|
||||||
|
try {
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append('category_no', categoryNo);
|
||||||
|
const data = await this.apiRequest('/webevent/selectListEvent.do', formData);
|
||||||
|
|
||||||
|
if (data.msgCode === '0') {
|
||||||
|
const today = new Date();
|
||||||
|
today.setHours(0, 0, 0, 0);
|
||||||
|
|
||||||
|
this.events = data.rows.map(row => {
|
||||||
|
// 지난 이벤트 판별: EVENT_END_DT가 있고 오늘보다 이전이면 expired
|
||||||
|
let isExpired = false;
|
||||||
|
if (row.EVENT_END_DT) {
|
||||||
|
const endDate = new Date(row.EVENT_END_DT);
|
||||||
|
endDate.setHours(23, 59, 59, 999);
|
||||||
|
isExpired = endDate < today;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
img: CDN_URL + row.THUMBNAIL_PATH,
|
||||||
|
title: row.TITLE,
|
||||||
|
desc: row.CONTENT,
|
||||||
|
meta: row.THUMBNAIL_BOTTOM_TXT,
|
||||||
|
price: {
|
||||||
|
before: Number(row.PRICE) || 0,
|
||||||
|
after: Number(row.DISCOUNT_PRICE) || 0
|
||||||
|
},
|
||||||
|
categoryDiv: row.CATEGORY_DIV_CD,
|
||||||
|
categoryNo: row.CATEGORY_NO,
|
||||||
|
postNo: row.POST_NO,
|
||||||
|
eventStartDt: row.EVENT_START_DT,
|
||||||
|
eventEndDt: row.EVENT_END_DT,
|
||||||
|
isExpired: isExpired
|
||||||
|
};
|
||||||
});
|
});
|
||||||
}
|
this.renderEvents();
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
* 시술 목록 가져오기
|
|
||||||
****************************************************************************/
|
|
||||||
function fn_SelectEventList(category_no){
|
|
||||||
$(".active").addClass("nonactive");
|
|
||||||
$(".active").removeClass("active");
|
|
||||||
|
|
||||||
$("#category_"+category_no).removeClass("nonactive");
|
|
||||||
$("#category_"+category_no).addClass("active");
|
|
||||||
|
|
||||||
|
|
||||||
let formData = new FormData();
|
|
||||||
formData.append('category_no', category_no);
|
|
||||||
|
|
||||||
$.ajax({
|
|
||||||
url: encodeURI('/webevent/selectListEvent.do'),
|
|
||||||
data: formData,
|
|
||||||
dataType: 'json',
|
|
||||||
processData: false,
|
|
||||||
contentType: false,
|
|
||||||
type: 'POST',
|
|
||||||
async: true,
|
|
||||||
success: function(data){
|
|
||||||
if(data.msgCode=='0'){
|
|
||||||
|
|
||||||
let totalCount = data.rows.length;
|
|
||||||
let listHTML = '';
|
|
||||||
if (0 < totalCount) {
|
|
||||||
for (let i = 0; i < data.rows.length; i++) {
|
|
||||||
listHTML += '<li class="fadeIn">';
|
|
||||||
listHTML += ' <a href="javascript:fn_moveDetail(' + data.rows[i].CATEGORY_DIV_CD +', ' + data.rows[i].CATEGORY_NO + ',' + data.rows[i].POST_NO + ');" class="event-card">';
|
|
||||||
listHTML += ' <div class="img_box">';
|
|
||||||
listHTML += ' <img src="https://intranet.bbgnetworks.com/uploadFiles/T00004/eventImg/20250203144112.png" alt="평일 오후1시-5시 / 피부 이벤트" class="">';
|
|
||||||
listHTML += ' </div>';
|
|
||||||
listHTML += ' <div class="txt-box">';
|
|
||||||
listHTML += ' <!-- BEST/NEW 아이콘 퍼블리싱 -->';
|
|
||||||
listHTML += ' <!-- __tit-best: best아이콘 __tit-new: new아이콘 -->';
|
|
||||||
listHTML += ' <div class="tit-txt">';
|
|
||||||
listHTML += ' <p class="multy-ellip2">' + data.rows[i].TITLE + '</p>';
|
|
||||||
listHTML += ' </div>';
|
|
||||||
listHTML += ' <span class="sub-txt max-line1 one-ellip">' + data.rows[i].THUMBNAIL_BOTTOM_TXT + '</span>';
|
|
||||||
listHTML += ' <div class="ab_cont">';
|
|
||||||
listHTML += ' <span class="cost"><del class="">';
|
|
||||||
if(data.rows[i].DISCOUNT_PRICE == null || data.rows[i].DISCOUNT_PRICE == undefined){
|
|
||||||
if(data.rows[i].PRICE == null || data.rows[i].PRICE == undefined){
|
|
||||||
listHTML += '0';
|
|
||||||
}else{
|
|
||||||
listHTML += (data.rows[i].PRICE).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
|
||||||
}
|
|
||||||
}else{
|
|
||||||
listHTML += (data.rows[i].DISCOUNT_PRICE).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
|
||||||
}
|
|
||||||
listHTML += ' </del>원</span>';
|
|
||||||
listHTML += ' <span class="discount">';
|
|
||||||
listHTML += ' <strong class="txt_num">';
|
|
||||||
if(data.rows[i].DISCOUNT_PRICE == null || data.rows[i].DISCOUNT_PRICE == undefined){
|
|
||||||
if(data.rows[i].PRICE == null || data.rows[i].PRICE == undefined){
|
|
||||||
listHTML += '0';
|
|
||||||
}else{
|
|
||||||
listHTML += (data.rows[i].PRICE).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
|
||||||
}
|
|
||||||
}else{
|
|
||||||
listHTML += (data.rows[i].DISCOUNT_PRICE).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
|
||||||
}
|
|
||||||
listHTML += ' </strong>원 부터 </span>';
|
|
||||||
listHTML += ' </div>';
|
|
||||||
listHTML += ' </div>';
|
|
||||||
listHTML += ' </a>';
|
|
||||||
listHTML += '</li>';
|
|
||||||
}
|
|
||||||
$("#detail_list").html(listHTML);
|
|
||||||
|
|
||||||
}else{
|
|
||||||
listHTML += '<li class="mt70">';
|
|
||||||
listHTML += '</li>';
|
|
||||||
$("#detail_list").html(listHTML);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
modalEvent.danger("조회 오류", data.msgDesc);
|
modalEvent.danger("조회 오류", data.msgDesc);
|
||||||
}
|
}
|
||||||
|
} catch (error) {
|
||||||
},
|
modalEvent.danger("조회 오류", "조회 중 오류가 발생하였습니다.");
|
||||||
error : function(xhr, status, error) {
|
|
||||||
modalEvent.danger("조회 오류", "조회 중 오류가 발생하였습니다. 잠시후 다시시도하십시오.");
|
|
||||||
},
|
|
||||||
beforeSend:function(){
|
|
||||||
// 로딩열기
|
|
||||||
$(".loading-image-layer").show();
|
|
||||||
},
|
|
||||||
complete:function(){
|
|
||||||
// 로딩닫기
|
|
||||||
$(".loading-image-layer").hide();
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
renderCategories() {
|
||||||
|
const html = this.categories.map((cat, idx) => `
|
||||||
|
<li class="category-item">
|
||||||
|
<a href="#" class="category-link ${idx === 0 ? 'active' : ''}"
|
||||||
|
data-category="${cat.CATEGORY_NO}">${cat.CATEGORY_NM}</a>
|
||||||
|
</li>
|
||||||
|
`).join('');
|
||||||
|
|
||||||
|
document.getElementById('category-list').innerHTML = html;
|
||||||
|
|
||||||
|
document.querySelectorAll('.category-link').forEach(link => {
|
||||||
|
link.addEventListener('click', (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
document.querySelectorAll('.category-link').forEach(item =>
|
||||||
|
item.classList.remove('active'));
|
||||||
|
link.classList.add('active');
|
||||||
|
this.loadEvents(link.dataset.category);
|
||||||
|
document.querySelector('.event-list').scrollTop = 0;
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function fn_moveDetail(category_div, category_no, post_no){
|
renderEvents() {
|
||||||
let pageMoveForm = document.createElement('form');
|
const html = this.events.map(event => {
|
||||||
let obj = document.createElement('input');
|
const expiredClass = event.isExpired ? ' expired' : '';
|
||||||
obj.setAttribute('type', 'hidden');
|
const expiredBadge = event.isExpired ? '<span class="expired-badge">종료된 이벤트</span>' : '';
|
||||||
obj.setAttribute('name', 'CATEGORY_DIV_CD');
|
|
||||||
obj.setAttribute('value', "0"+category_div);
|
|
||||||
pageMoveForm.appendChild(obj);
|
|
||||||
|
|
||||||
let obj2 = document.createElement('input');
|
// 이벤트 기간 표시
|
||||||
obj2.setAttribute('type', 'hidden');
|
let dateHtml = '';
|
||||||
obj2.setAttribute('name', 'CATEGORY_NO');
|
if (event.eventStartDt || event.eventEndDt) {
|
||||||
obj2.setAttribute('value', category_no);
|
const startStr = event.eventStartDt || '';
|
||||||
pageMoveForm.appendChild(obj2);
|
const endStr = event.eventEndDt || '';
|
||||||
|
if (startStr && endStr) {
|
||||||
let obj3 = document.createElement('input');
|
dateHtml = `<div class="event-date">📅 ${startStr} ~ ${endStr}</div>`;
|
||||||
obj3.setAttribute('type', 'hidden');
|
} else if (endStr) {
|
||||||
obj3.setAttribute('name', 'POST_NO');
|
dateHtml = `<div class="event-date">📅 ~ ${endStr}</div>`;
|
||||||
obj3.setAttribute('value', post_no);
|
}
|
||||||
pageMoveForm.appendChild(obj3);
|
|
||||||
|
|
||||||
pageMoveForm.setAttribute('method', 'post');
|
|
||||||
pageMoveForm.setAttribute('action', '/webevent/selectEventDetailIntro.do');
|
|
||||||
document.body.appendChild(pageMoveForm);
|
|
||||||
pageMoveForm.submit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//초기화
|
return `
|
||||||
fn_init();
|
<div class="event-card${expiredClass}" data-category-div="${event.categoryDiv}"
|
||||||
|
data-category-no="${event.categoryNo}" data-post-no="${event.postNo}"
|
||||||
|
data-expired="${event.isExpired}">
|
||||||
|
${expiredBadge}
|
||||||
|
<div class="event-img">
|
||||||
|
<img src="${event.img}" alt="${event.title}">
|
||||||
|
</div>
|
||||||
|
<div class="event-info">
|
||||||
|
<div class="event-title">${event.title}</div>
|
||||||
|
${event.meta ? `<div class="event-meta">${event.meta}</div>` : ''}
|
||||||
|
${dateHtml}
|
||||||
|
<div class="event-price">
|
||||||
|
${event.price.before !== event.price.after
|
||||||
|
? `<span style="text-decoration:line-through; color:#9ca3af; font-size:0.95em; margin-right:8px;">
|
||||||
|
${event.price.before.toLocaleString()}원
|
||||||
|
</span>`
|
||||||
|
: ''}
|
||||||
|
${event.price.after.toLocaleString()}원 부터
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`}).join('');
|
||||||
|
|
||||||
|
document.getElementById('event-grid').innerHTML = html;
|
||||||
|
|
||||||
|
// 카드 클릭 이벤트 추가
|
||||||
|
document.querySelectorAll('.event-card').forEach(card => {
|
||||||
|
card.addEventListener('click', () => {
|
||||||
|
const isExpired = card.dataset.expired === 'true';
|
||||||
|
|
||||||
|
if (isExpired) {
|
||||||
|
// 지난 이벤트 → 팝업 표시
|
||||||
|
this.showExpiredPopup();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const categoryDiv = card.dataset.categoryDiv;
|
||||||
|
const categoryNo = card.dataset.categoryNo;
|
||||||
|
const postNo = card.dataset.postNo;
|
||||||
|
this.goToDetail(categoryDiv, categoryNo, postNo);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
showExpiredPopup() {
|
||||||
|
const overlay = document.getElementById('expired-popup');
|
||||||
|
if (overlay) {
|
||||||
|
overlay.classList.add('active');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hideExpiredPopup() {
|
||||||
|
const overlay = document.getElementById('expired-popup');
|
||||||
|
if (overlay) {
|
||||||
|
overlay.classList.remove('active');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
goToDetail(categoryDiv, categoryNo, postNo) {
|
||||||
|
const form = document.createElement('form');
|
||||||
|
form.method = 'get';
|
||||||
|
form.action = '/webevent/selectEventDetailIntro.do';
|
||||||
|
|
||||||
|
const fields = [
|
||||||
|
{ name: 'CATEGORY_DIV_CD', value: categoryDiv },
|
||||||
|
{ name: 'CATEGORY_NO', value: categoryNo },
|
||||||
|
{ name: 'POST_NO', value: postNo }
|
||||||
|
];
|
||||||
|
|
||||||
|
fields.forEach(field => {
|
||||||
|
const input = document.createElement('input');
|
||||||
|
input.type = 'hidden';
|
||||||
|
input.name = field.name;
|
||||||
|
input.value = field.value;
|
||||||
|
form.appendChild(input);
|
||||||
|
});
|
||||||
|
|
||||||
|
document.body.appendChild(form);
|
||||||
|
form.submit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const eventManager = new EventManager();
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
class ReviewDetailManager {
|
||||||
|
constructor() {
|
||||||
|
this.quill = null;
|
||||||
|
this.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
async init() {
|
||||||
|
if (!muProcedureReviewId) { this.showError('잘못된 접근입니다.'); return; }
|
||||||
|
await this.loadReview();
|
||||||
|
}
|
||||||
|
|
||||||
|
async apiRequest(url, data) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
$.ajax({
|
||||||
|
url: encodeURI(url), data: data, dataType: 'json',
|
||||||
|
processData: false, contentType: false, type: 'POST',
|
||||||
|
success: resolve, error: reject
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async loadReview() {
|
||||||
|
try {
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append('muProcedureReviewId', muProcedureReviewId);
|
||||||
|
const data = await this.apiRequest('/webreview/selectProcedureReview.do', formData);
|
||||||
|
if (data.msgCode === '0' && data.rows) {
|
||||||
|
this.renderReview(data.rows);
|
||||||
|
} else {
|
||||||
|
this.showError('게시글을 찾을 수 없습니다.');
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
this.showError('게시글 조회 중 오류가 발생하였습니다.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
renderReview(review) {
|
||||||
|
document.getElementById('review-title').textContent = review.title || '';
|
||||||
|
document.getElementById('breadcrumb-title').textContent = review.title || '상세보기';
|
||||||
|
document.getElementById('review-date').textContent = review.writeDate || '';
|
||||||
|
document.getElementById('review-views').textContent = review.viewCount || 0;
|
||||||
|
|
||||||
|
const tagsContainer = document.getElementById('review-tags');
|
||||||
|
if (review.hashtag) {
|
||||||
|
const tags = review.hashtag.split(',').map(t => t.trim()).filter(t => t);
|
||||||
|
tagsContainer.innerHTML = tags.map(tag => `<span class="review-tag">#${tag}</span>`).join('');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Quill Delta JSON 본문 렌더링
|
||||||
|
const contentDiv = document.getElementById('review-content');
|
||||||
|
if (review.content) {
|
||||||
|
try {
|
||||||
|
const decoded = decodeURIComponent(escape(atob(review.content)));
|
||||||
|
const delta = JSON.parse(decoded);
|
||||||
|
|
||||||
|
contentDiv.innerHTML = '';
|
||||||
|
this.quill = new Quill(contentDiv, {
|
||||||
|
readOnly: true,
|
||||||
|
modules: { toolbar: false },
|
||||||
|
theme: 'snow'
|
||||||
|
});
|
||||||
|
this.quill.setContents(delta);
|
||||||
|
|
||||||
|
const toolbar = contentDiv.parentElement.querySelector('.ql-toolbar');
|
||||||
|
if (toolbar) toolbar.style.display = 'none';
|
||||||
|
const container = contentDiv.parentElement.querySelector('.ql-container');
|
||||||
|
if (container) { container.style.border = 'none'; container.style.fontSize = '16px'; }
|
||||||
|
} catch (e) {
|
||||||
|
try {
|
||||||
|
const html = decodeURIComponent(escape(atob(review.content)));
|
||||||
|
contentDiv.innerHTML = html;
|
||||||
|
} catch (e2) {
|
||||||
|
contentDiv.innerHTML = review.content;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
contentDiv.innerHTML = '<p style="color:#9ca3af;text-align:center;">내용이 없습니다.</p>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
showError(msg) {
|
||||||
|
document.getElementById('review-content').innerHTML = `
|
||||||
|
<div style="text-align:center;padding:3rem;color:#6b7280;">
|
||||||
|
<div style="font-size:2rem;margin-bottom:1rem;">😔</div><div>${msg}</div>
|
||||||
|
</div>`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const reviewDetailManager = new ReviewDetailManager();
|
||||||
@@ -0,0 +1,205 @@
|
|||||||
|
class ReviewListManager {
|
||||||
|
constructor() {
|
||||||
|
this.reviews = [];
|
||||||
|
this.currentPage = 1;
|
||||||
|
this.pageSize = 9;
|
||||||
|
this.totalCount = 0;
|
||||||
|
this.categoryDivCd = '08'; // 쁘띠센터
|
||||||
|
this.sliders = {};
|
||||||
|
this.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
async init() {
|
||||||
|
this.bindEvents();
|
||||||
|
await this.loadReviews();
|
||||||
|
}
|
||||||
|
|
||||||
|
bindEvents() {
|
||||||
|
document.getElementById('btnSearch').addEventListener('click', () => {
|
||||||
|
this.currentPage = 1;
|
||||||
|
this.loadReviews();
|
||||||
|
});
|
||||||
|
document.getElementById('searchTitle').addEventListener('keypress', (e) => {
|
||||||
|
if (e.key === 'Enter') { this.currentPage = 1; this.loadReviews(); }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async apiRequest(url, data) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
$.ajax({
|
||||||
|
url: encodeURI(url), data: data, dataType: 'json',
|
||||||
|
processData: false, contentType: false, type: 'POST',
|
||||||
|
success: resolve, error: reject
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async loadReviews() {
|
||||||
|
try {
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append('categoryDivCd', this.categoryDivCd);
|
||||||
|
formData.append('start', (this.currentPage - 1) * this.pageSize);
|
||||||
|
formData.append('limit', this.pageSize);
|
||||||
|
const searchTitle = document.getElementById('searchTitle').value.trim();
|
||||||
|
if (searchTitle) formData.append('title', searchTitle);
|
||||||
|
|
||||||
|
const data = await this.apiRequest('/webreview/selectListProcedureReview.do', formData);
|
||||||
|
if (data.msgCode === '0') {
|
||||||
|
this.reviews = data.rows || [];
|
||||||
|
this.totalCount = parseInt(data.totalCount) || 0;
|
||||||
|
this.renderReviews();
|
||||||
|
this.renderPagination();
|
||||||
|
} else {
|
||||||
|
this.showEmpty('조회 중 오류가 발생하였습니다.');
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
this.showEmpty('조회 중 오류가 발생하였습니다.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extractImages(content) {
|
||||||
|
if (!content) return [];
|
||||||
|
try {
|
||||||
|
const decoded = decodeURIComponent(escape(atob(content)));
|
||||||
|
const delta = JSON.parse(decoded);
|
||||||
|
if (delta.ops) {
|
||||||
|
return delta.ops
|
||||||
|
.filter(op => op.insert && typeof op.insert === 'object' && op.insert.image)
|
||||||
|
.map(op => op.insert.image);
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
} catch (e) { return []; }
|
||||||
|
}
|
||||||
|
|
||||||
|
extractSummary(content) {
|
||||||
|
if (!content) return '';
|
||||||
|
try {
|
||||||
|
const decoded = decodeURIComponent(escape(atob(content)));
|
||||||
|
const delta = JSON.parse(decoded);
|
||||||
|
if (delta.ops) {
|
||||||
|
const text = delta.ops
|
||||||
|
.filter(op => typeof op.insert === 'string')
|
||||||
|
.map(op => op.insert).join('').replace(/\n/g, ' ').trim();
|
||||||
|
return text.length > 100 ? text.substring(0, 100) + '...' : text;
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
} catch (e) { return ''; }
|
||||||
|
}
|
||||||
|
|
||||||
|
buildSliderHtml(images, cardIdx) {
|
||||||
|
if (images.length === 0) return '<div class="review-no-image">📷</div>';
|
||||||
|
const imagesHtml = images.map(src => `<img src="${src}" alt="고객후기" loading="lazy" />`).join('');
|
||||||
|
const dotsHtml = images.length > 1
|
||||||
|
? `<div class="slider-dots">${images.map((_, i) =>
|
||||||
|
`<button class="slider-dot ${i === 0 ? 'active' : ''}" data-idx="${i}"></button>`).join('')}</div>` : '';
|
||||||
|
const arrowsHtml = images.length > 1
|
||||||
|
? `<button class="slider-arrow prev" data-dir="-1">‹</button><button class="slider-arrow next" data-dir="1">›</button>` : '';
|
||||||
|
const countHtml = images.length > 1
|
||||||
|
? `<span class="slider-count">1 / ${images.length}</span>` : '';
|
||||||
|
return `<div class="review-slider" data-total="${images.length}" data-current="0">
|
||||||
|
<div class="review-slider-track">${imagesHtml}</div>${arrowsHtml}${dotsHtml}${countHtml}</div>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
renderReviews() {
|
||||||
|
const grid = document.getElementById('review-grid');
|
||||||
|
if (this.reviews.length === 0) {
|
||||||
|
grid.innerHTML = `<div class="empty-state"><div class="icon">📝</div><div class="message">등록된 고객후기가 없습니다.</div></div>`;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
grid.innerHTML = this.reviews.map((review, idx) => {
|
||||||
|
const images = this.extractImages(review.summary || review.content);
|
||||||
|
const summaryText = this.extractSummary(review.summary || review.content);
|
||||||
|
const sliderHtml = this.buildSliderHtml(images, idx);
|
||||||
|
let tagsHtml = '';
|
||||||
|
if (review.hashtag) {
|
||||||
|
const tags = review.hashtag.split(',').map(t => t.trim()).filter(t => t);
|
||||||
|
tagsHtml = `<div class="review-card-tags">${tags.slice(0, 3).map(tag =>
|
||||||
|
`<span class="review-tag">#${tag}</span>`).join('')}</div>`;
|
||||||
|
}
|
||||||
|
return `<div class="review-card" data-id="${review.muProcedureReviewId}">
|
||||||
|
${sliderHtml}
|
||||||
|
<div class="review-card-body">
|
||||||
|
<div class="review-card-title">${this.escapeHtml(review.title)}</div>
|
||||||
|
<div class="review-card-summary">${summaryText}</div>
|
||||||
|
${tagsHtml}
|
||||||
|
<div class="review-card-footer">
|
||||||
|
<span class="date">${review.writeDate}</span>
|
||||||
|
<span class="views">👁 ${review.viewCount || 0}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>`;
|
||||||
|
}).join('');
|
||||||
|
|
||||||
|
this.bindSliderEvents();
|
||||||
|
|
||||||
|
grid.querySelectorAll('.review-card').forEach(card => {
|
||||||
|
card.addEventListener('click', (e) => {
|
||||||
|
if (e.target.closest('.slider-arrow') || e.target.closest('.slider-dot')) return;
|
||||||
|
location.href = `/webreview/selectProcedureReviewIntro.do?muProcedureReviewId=${card.dataset.id}`;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
bindSliderEvents() {
|
||||||
|
document.querySelectorAll('.review-slider').forEach(slider => {
|
||||||
|
const total = parseInt(slider.dataset.total);
|
||||||
|
if (total <= 1) return;
|
||||||
|
const track = slider.querySelector('.review-slider-track');
|
||||||
|
const dots = slider.querySelectorAll('.slider-dot');
|
||||||
|
const countEl = slider.querySelector('.slider-count');
|
||||||
|
|
||||||
|
const goTo = (idx) => {
|
||||||
|
const current = Math.max(0, Math.min(idx, total - 1));
|
||||||
|
slider.dataset.current = current;
|
||||||
|
track.style.transform = `translateX(-${current * 100}%)`;
|
||||||
|
dots.forEach((d, i) => d.classList.toggle('active', i === current));
|
||||||
|
if (countEl) countEl.textContent = `${current + 1} / ${total}`;
|
||||||
|
};
|
||||||
|
slider.querySelectorAll('.slider-arrow').forEach(arrow => {
|
||||||
|
arrow.addEventListener('click', (e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
let next = parseInt(slider.dataset.current) + parseInt(arrow.dataset.dir);
|
||||||
|
if (next < 0) next = total - 1;
|
||||||
|
if (next >= total) next = 0;
|
||||||
|
goTo(next);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
dots.forEach(dot => {
|
||||||
|
dot.addEventListener('click', (e) => { e.stopPropagation(); goTo(parseInt(dot.dataset.idx)); });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
renderPagination() {
|
||||||
|
const area = document.getElementById('pagination-area');
|
||||||
|
const totalPages = Math.ceil(this.totalCount / this.pageSize);
|
||||||
|
if (totalPages <= 1) { area.innerHTML = ''; return; }
|
||||||
|
let html = `<button class="page-btn ${this.currentPage === 1 ? 'disabled' : ''}" data-page="${this.currentPage - 1}" ${this.currentPage === 1 ? 'disabled' : ''}>‹</button>`;
|
||||||
|
const startPage = Math.max(1, this.currentPage - 2);
|
||||||
|
const endPage = Math.min(totalPages, startPage + 4);
|
||||||
|
for (let i = startPage; i <= endPage; i++) {
|
||||||
|
html += `<button class="page-btn ${i === this.currentPage ? 'active' : ''}" data-page="${i}">${i}</button>`;
|
||||||
|
}
|
||||||
|
html += `<button class="page-btn ${this.currentPage === totalPages ? 'disabled' : ''}" data-page="${this.currentPage + 1}" ${this.currentPage === totalPages ? 'disabled' : ''}>›</button>`;
|
||||||
|
area.innerHTML = html;
|
||||||
|
area.querySelectorAll('.page-btn:not(.disabled)').forEach(btn => {
|
||||||
|
btn.addEventListener('click', () => {
|
||||||
|
this.currentPage = parseInt(btn.dataset.page);
|
||||||
|
this.loadReviews();
|
||||||
|
window.scrollTo({ top: 0, behavior: 'smooth' });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
showEmpty(msg) {
|
||||||
|
document.getElementById('review-grid').innerHTML = `<div class="empty-state"><div class="icon">⚠️</div><div class="message">${msg}</div></div>`;
|
||||||
|
document.getElementById('pagination-area').innerHTML = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
escapeHtml(str) {
|
||||||
|
if (!str) return '';
|
||||||
|
return str.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"').replace(/'/g, ''');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const reviewListManager = new ReviewListManager();
|
||||||
230
src/main/resources/static/sitemap.xml
Normal file
@@ -0,0 +1,230 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd">
|
||||||
|
<url>
|
||||||
|
<loc>https://petit.madeu.co.kr/</loc>
|
||||||
|
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||||
|
<priority>1.00</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://petit.madeu.co.kr/index</loc>
|
||||||
|
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||||
|
<priority>0.80</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://petit.madeu.co.kr/webintroduction/selectIntroductionHospitalIntro.do</loc>
|
||||||
|
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||||
|
<priority>0.80</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://petit.madeu.co.kr/webintroduction/selectIntroductionStaffIntro.do</loc>
|
||||||
|
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||||
|
<priority>0.80</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://petit.madeu.co.kr/webintroduction/selectIntroductionWayIntro.do</loc>
|
||||||
|
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||||
|
<priority>0.80</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://petit.madeu.co.kr/webservice/selectServiceIntro.do?categoryNo=4</loc>
|
||||||
|
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||||
|
<priority>0.80</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://petit.madeu.co.kr/webservice/selectServiceDetailIntro.do?categoryDivCd=03&categoryNo=4&postNo=8</loc>
|
||||||
|
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||||
|
<priority>0.80</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://petit.madeu.co.kr/webservice/selectServiceDetailIntro.do?categoryDivCd=03&categoryNo=4&postNo=2</loc>
|
||||||
|
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||||
|
<priority>0.80</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://petit.madeu.co.kr/webservice/selectServiceDetailIntro.do?categoryDivCd=03&categoryNo=4&postNo=3</loc>
|
||||||
|
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||||
|
<priority>0.80</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://petit.madeu.co.kr/webservice/selectServiceDetailIntro.do?categoryDivCd=03&categoryNo=4&postNo=4</loc>
|
||||||
|
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||||
|
<priority>0.80</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://petit.madeu.co.kr/webservice/selectServiceDetailIntro.do?categoryDivCd=03&categoryNo=4&postNo=5</loc>
|
||||||
|
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||||
|
<priority>0.80</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://petit.madeu.co.kr/webservice/selectServiceDetailIntro.do?categoryDivCd=03&categoryNo=4&postNo=6</loc>
|
||||||
|
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||||
|
<priority>0.80</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://petit.madeu.co.kr/webservice/selectServiceDetailIntro.do?categoryDivCd=03&categoryNo=4&postNo=7</loc>
|
||||||
|
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||||
|
<priority>0.80</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://petit.madeu.co.kr/webservice/selectServiceIntro.do?categoryNo=2</loc>
|
||||||
|
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||||
|
<priority>0.80</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://petit.madeu.co.kr/webservice/selectServiceDetailIntro.do?categoryDivCd=03&categoryNo=2&postNo=3</loc>
|
||||||
|
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||||
|
<priority>0.80</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://petit.madeu.co.kr/webservice/selectServiceDetailIntro.do?categoryDivCd=03&categoryNo=2&postNo=4</loc>
|
||||||
|
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||||
|
<priority>0.80</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://petit.madeu.co.kr/webservice/selectServiceDetailIntro.do?categoryDivCd=03&categoryNo=2&postNo=5</loc>
|
||||||
|
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||||
|
<priority>0.80</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://petit.madeu.co.kr/webservice/selectServiceIntro.do?categoryNo=3</loc>
|
||||||
|
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||||
|
<priority>0.80</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://petit.madeu.co.kr/webservice/selectServiceDetailIntro.do?categoryDivCd=03&categoryNo=3&postNo=6</loc>
|
||||||
|
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||||
|
<priority>0.80</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://petit.madeu.co.kr/webservice/selectServiceDetailIntro.do?categoryDivCd=03&categoryNo=3&postNo=10</loc>
|
||||||
|
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||||
|
<priority>0.80</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://petit.madeu.co.kr/webservice/selectServiceDetailIntro.do?categoryDivCd=03&categoryNo=3&postNo=11</loc>
|
||||||
|
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||||
|
<priority>0.80</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://petit.madeu.co.kr/webservice/selectServiceIntro.do?categoryNo=5</loc>
|
||||||
|
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||||
|
<priority>0.80</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://petit.madeu.co.kr/webservice/selectServiceDetailIntro.do?categoryDivCd=03&categoryNo=5&postNo=5</loc>
|
||||||
|
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||||
|
<priority>0.80</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://petit.madeu.co.kr/webservice/selectServiceDetailIntro.do?categoryDivCd=03&categoryNo=5&postNo=6</loc>
|
||||||
|
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||||
|
<priority>0.80</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://petit.madeu.co.kr/webservice/selectServiceDetailIntro.do?categoryDivCd=03&categoryNo=5&postNo=7</loc>
|
||||||
|
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||||
|
<priority>0.80</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://petit.madeu.co.kr/webservice/selectServiceDetailIntro.do?categoryDivCd=03&categoryNo=5&postNo=8</loc>
|
||||||
|
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||||
|
<priority>0.80</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://petit.madeu.co.kr/webservice/selectServiceDetailIntro.do?categoryDivCd=03&categoryNo=5&postNo=9</loc>
|
||||||
|
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||||
|
<priority>0.80</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://petit.madeu.co.kr/webservice/selectServiceIntro.do?categoryNo=1</loc>
|
||||||
|
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||||
|
<priority>0.80</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://petit.madeu.co.kr/webservice/selectServiceDetailIntro.do?categoryDivCd=03&categoryNo=1&postNo=10</loc>
|
||||||
|
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||||
|
<priority>0.80</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://petit.madeu.co.kr/webservice/selectServiceDetailIntro.do?categoryDivCd=03&categoryNo=1&postNo=3</loc>
|
||||||
|
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||||
|
<priority>0.80</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://petit.madeu.co.kr/webservice/selectServiceDetailIntro.do?categoryDivCd=03&categoryNo=1&postNo=6</loc>
|
||||||
|
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||||
|
<priority>0.80</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://petit.madeu.co.kr/webservice/selectServiceDetailIntro.do?categoryDivCd=03&categoryNo=1&postNo=11</loc>
|
||||||
|
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||||
|
<priority>0.80</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://petit.madeu.co.kr/webservice/selectServiceIntro.do?categoryNo=6</loc>
|
||||||
|
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||||
|
<priority>0.80</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://petit.madeu.co.kr/webservice/selectServiceDetailIntro.do?categoryDivCd=03&categoryNo=6&postNo=7</loc>
|
||||||
|
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||||
|
<priority>0.80</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://petit.madeu.co.kr/webservice/selectServiceDetailIntro.do?categoryDivCd=03&categoryNo=6&postNo=8</loc>
|
||||||
|
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||||
|
<priority>0.80</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://petit.madeu.co.kr/webservice/selectServiceDetailIntro.do?categoryDivCd=03&categoryNo=6&postNo=9</loc>
|
||||||
|
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||||
|
<priority>0.80</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://petit.madeu.co.kr/webservice/selectServiceDetailIntro.do?categoryDivCd=03&categoryNo=6&postNo=10</loc>
|
||||||
|
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||||
|
<priority>0.80</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://petit.madeu.co.kr/webservice/selectServiceDetailIntro.do?categoryDivCd=03&categoryNo=6&postNo=11</loc>
|
||||||
|
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||||
|
<priority>0.80</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://petit.madeu.co.kr/webservice/selectServiceIntro.do?categoryNo=7</loc>
|
||||||
|
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||||
|
<priority>0.80</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://petit.madeu.co.kr/webservice/selectServiceDetailIntro.do?categoryDivCd=03&categoryNo=7&postNo=8</loc>
|
||||||
|
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||||
|
<priority>0.80</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://petit.madeu.co.kr/webservice/selectServiceDetailIntro.do?categoryDivCd=03&categoryNo=7&postNo=9</loc>
|
||||||
|
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||||
|
<priority>0.80</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://petit.madeu.co.kr/webevent/selectListWebEventIntro.do</loc>
|
||||||
|
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||||
|
<priority>0.80</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://petit.madeu.co.kr/webphoto/selectListWebPhotoIntro.do</loc>
|
||||||
|
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||||
|
<priority>0.80</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://petit.madeu.co.kr/webaccept/acceptSite.do</loc>
|
||||||
|
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||||
|
<priority>0.80</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://petit.madeu.co.kr/webaccept/acceptPrivacy.do</loc>
|
||||||
|
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||||
|
<priority>0.80</priority>
|
||||||
|
</url>
|
||||||
|
</urlset>
|
||||||
@@ -1,8 +1,6 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html xmlns="http://www.w3.org/1999/xhtml"
|
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
|
||||||
xmlns:th="http://www.thymeleaf.org"
|
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{/web/layout/layout}">
|
||||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
|
||||||
layout:decorate="~{/web/layout/layout}">
|
|
||||||
<th:block layout:fragment="layoutCss">
|
<th:block layout:fragment="layoutCss">
|
||||||
<link rel="stylesheet" href="/css/web/index.css">
|
<link rel="stylesheet" href="/css/web/index.css">
|
||||||
<link rel="stylesheet" href="/css/web/instagram-swiper-custom.css?v1.0">
|
<link rel="stylesheet" href="/css/web/instagram-swiper-custom.css?v1.0">
|
||||||
@@ -25,24 +23,24 @@
|
|||||||
<div class="swiper cont1_swiper">
|
<div class="swiper cont1_swiper">
|
||||||
<div class="swiper-wrapper">
|
<div class="swiper-wrapper">
|
||||||
<div class="swiper-slide">
|
<div class="swiper-slide">
|
||||||
<img class="pc" src="/image/web/petit_content_lifting.JPG" alt="img">
|
<img class="pc" src="/image/signature/20251024/레이저리프팅.jpg" alt="img">
|
||||||
<img class="mb" src="/image/web/petit_content_lifting.JPG" alt="img">
|
<img class="mb" src="/image/signature/20251024/레이저리프팅.jpg" alt="img">
|
||||||
</div>
|
</div>
|
||||||
<div class="swiper-slide">
|
<div class="swiper-slide">
|
||||||
<img class="pc" src="/image/web/petit_content_botox.JPG" alt="img">
|
<img class="pc" src="/image/signature/20251024/쉬다주사(Face).jpg" alt="img">
|
||||||
<img class="mb" src="/image/web/petit_content_botox.JPG" alt="img">
|
<img class="mb" src="/image/signature/20251024/쉬다주사(Face).jpg" alt="img">
|
||||||
</div>
|
</div>
|
||||||
<div class="swiper-slide">
|
<div class="swiper-slide">
|
||||||
<img class="pc" src="/image/web/petit_content_booster.JPG" alt="img">
|
<img class="pc" src="/image/signature/20251024/스컬트라.jpg" alt="img">
|
||||||
<img class="mb" src="/image/web/petit_content_booster.JPG" alt="img">
|
<img class="mb" src="/image/signature/20251024/스컬트라.jpg" alt="img">
|
||||||
</div>
|
</div>
|
||||||
<div class="swiper-slide">
|
<div class="swiper-slide">
|
||||||
<img class="pc" src="/image/web/petit_content_waxing.JPG" alt="img">
|
<img class="pc" src="/image/signature/20251024/스킨부스터.jpg" alt="img">
|
||||||
<img class="mb" src="/image/web/petit_content_waxing.JPG" alt="img">
|
<img class="mb" src="/image/signature/20251024/스킨부스터.jpg" alt="img">
|
||||||
</div>
|
</div>
|
||||||
<div class="swiper-slide">
|
<div class="swiper-slide">
|
||||||
<img class="pc" src="/image/web/petit_content_filler.JPG" alt="img">
|
<img class="pc" src="/image/signature/20251024/필러.jpg" alt="img">
|
||||||
<img class="mb" src="/image/web/petit_content_filler.JPG" alt="img">
|
<img class="mb" src="/image/signature/20251024/필러.jpg" alt="img">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="swiper-pagination cont1_swiper_pagination"></div>
|
<div class="swiper-pagination cont1_swiper_pagination"></div>
|
||||||
@@ -73,24 +71,28 @@
|
|||||||
<div class="swiper cont2_swiper">
|
<div class="swiper cont2_swiper">
|
||||||
<div class="swiper-wrapper">
|
<div class="swiper-wrapper">
|
||||||
<div class="swiper-slide">
|
<div class="swiper-slide">
|
||||||
<img class="pc" src="/image/web/petit_machine_thermage.jpg" alt="img" style="cursor:pointer">
|
<img class="pc" src="/image/equip/20260313/써마지FLX.jpg" alt="img" style="cursor:pointer">
|
||||||
<img class="mb" src="/image/web/petit_machine_thermage.jpg" alt="img" style="cursor:pointer">
|
<img class="mb" src="/image/equip/20260313/써마지FLX.jpg" alt="img" style="cursor:pointer">
|
||||||
</div>
|
</div>
|
||||||
<div class="swiper-slide">
|
<div class="swiper-slide">
|
||||||
<img class="pc" src="/image/web/petit_machine_ultherapy.jpg" alt="img" style="cursor:pointer">
|
<img class="pc" src="/image/equip/20260313/울쎄라.jpg" alt="img" style="cursor:pointer">
|
||||||
<img class="mb" src="/image/web/petit_machine_ultherapy.jpg" alt="img" style="cursor:pointer">
|
<img class="mb" src="/image/equip/20260313/울쎄라.jpg" alt="img" style="cursor:pointer">
|
||||||
</div>
|
</div>
|
||||||
<div class="swiper-slide">
|
<div class="swiper-slide">
|
||||||
<img class="pc" src="/image/web/petit_machine_stemcell.jpg" alt="img" style="cursor:pointer">
|
<img class="pc" src="/image/equip/20260313/온다리프팅(Face).jpg" alt="img"
|
||||||
<img class="mb" src="/image/web/petit_machine_stemcell.jpg" alt="img" style="cursor:pointer">
|
style="cursor:pointer">
|
||||||
|
<img class="mb" src="/image/equip/20260313/온다리프팅(Face).jpg" alt="img"
|
||||||
|
style="cursor:pointer">
|
||||||
</div>
|
</div>
|
||||||
<div class="swiper-slide">
|
<div class="swiper-slide">
|
||||||
<img class="pc" src="/image/web/petit_machine_tuneface.jpg" alt="img" style="cursor:pointer">
|
<img class="pc" src="/image/equip/20260313/티타늄리프팅(Face).jpg" alt="img"
|
||||||
<img class="mb" src="/image/web/petit_machine_tuneface.jpg" alt="img" style="cursor:pointer">
|
style="cursor:pointer">
|
||||||
|
<img class="mb" src="/image/equip/20260313/티타늄리프팅(Face).jpg" alt="img"
|
||||||
|
style="cursor:pointer">
|
||||||
</div>
|
</div>
|
||||||
<div class="swiper-slide">
|
<div class="swiper-slide">
|
||||||
<img class="pc" src="/image/web/petit_machine_lifting.jpg" alt="img" style="cursor:pointer">
|
<img class="pc" src="/image/equip/20260313/튠페이스.jpg" alt="img" style="cursor:pointer">
|
||||||
<img class="mb" src="/image/web/petit_machine_lifting.jpg" alt="img" style="cursor:pointer">
|
<img class="mb" src="/image/equip/20260313/튠페이스.jpg" alt="img" style="cursor:pointer">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="swiper-pagination cont2_swiper_pagination"></div>
|
<div class="swiper-pagination cont2_swiper_pagination"></div>
|
||||||
@@ -104,7 +106,8 @@
|
|||||||
MADE U 인스타그램<br />
|
MADE U 인스타그램<br />
|
||||||
<span>@madeu_gn</span>
|
<span>@madeu_gn</span>
|
||||||
</h3>
|
</h3>
|
||||||
<button class="more_btn" onClick="window.open('https://instagram.com/madeu_gn')">View more ≫</button>
|
<button class="more_btn" onClick="window.open('https://instagram.com/madeu_gn')">View more
|
||||||
|
≫</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="instagram_btm" id="instagramFeed">
|
<div class="instagram_btm" id="instagramFeed">
|
||||||
<div class="swiper instagram_swiper">
|
<div class="swiper instagram_swiper">
|
||||||
@@ -147,4 +150,5 @@
|
|||||||
</script>
|
</script>
|
||||||
<script src="/js/web/index.js"></script>
|
<script src="/js/web/index.js"></script>
|
||||||
</th:block>
|
</th:block>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
@@ -1,8 +1,6 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html xmlns="http://www.w3.org/1999/xhtml"
|
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
|
||||||
xmlns:th="http://www.thymeleaf.org"
|
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{/web/layout/layout}">
|
||||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
|
||||||
layout:decorate="~{/web/layout/layout}">
|
|
||||||
<th:block layout:fragment="layoutCss">
|
<th:block layout:fragment="layoutCss">
|
||||||
<link rel="stylesheet" href="/css/web/introduction/introductionHospitalSelect.css?v1.0">
|
<link rel="stylesheet" href="/css/web/introduction/introductionHospitalSelect.css?v1.0">
|
||||||
</th:block>
|
</th:block>
|
||||||
@@ -87,7 +85,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="equipment-info">
|
<div class="equipment-info">
|
||||||
<h3 class="equipment-name">써마지</h3>
|
<h3 class="equipment-name">써마지</h3>
|
||||||
<p class="equipment-desc">깊은 탄력과 리프팅을 동시에</p>
|
<!-- <p class="equipment-desc">깊은 탄력과 리프팅을 동시에</p> -->
|
||||||
<p class="equipment-price"><!-- 1,800,000<span>부터</span> --></p>
|
<p class="equipment-price"><!-- 1,800,000<span>부터</span> --></p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -98,7 +96,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="equipment-info">
|
<div class="equipment-info">
|
||||||
<h3 class="equipment-name">울쎄라</h3>
|
<h3 class="equipment-name">울쎄라</h3>
|
||||||
<p class="equipment-desc">깊은 탄력과 리프팅을 동시에</p>
|
<!-- <p class="equipment-desc">깊은 탄력과 리프팅을 동시에</p> -->
|
||||||
<p class="equipment-price"><!-- 400,000<span>부터</span> --></p>
|
<p class="equipment-price"><!-- 400,000<span>부터</span> --></p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -109,18 +107,27 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="equipment-info">
|
<div class="equipment-info">
|
||||||
<h3 class="equipment-name">티타늄리프팅</h3>
|
<h3 class="equipment-name">티타늄리프팅</h3>
|
||||||
<p class="equipment-desc">깊은 탄력과 리프팅을 동시에</p>
|
<!-- <p class="equipment-desc">깊은 탄력과 리프팅을 동시에</p> -->
|
||||||
<p class="equipment-price"><!-- 600,000<span>부터</span> --></p>
|
<p class="equipment-price"><!-- 600,000<span>부터</span> --></p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="equipment-card">
|
||||||
|
<div class="equipment-image">
|
||||||
|
<img src="/image/equip/온다리프팅.jpg" alt="온다리프팅">
|
||||||
|
</div>
|
||||||
|
<div class="equipment-info">
|
||||||
|
<h3 class="equipment-name">온다리프팅</h3>
|
||||||
|
<!-- <p class="equipment-desc">깊은 탄력과 리프팅을 동시에</p> -->
|
||||||
|
<!-- <p class="equipment-price">165,000<span>부터</span></p> -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="equipment-card">
|
<div class="equipment-card">
|
||||||
<div class="equipment-image">
|
<div class="equipment-image">
|
||||||
<img src="/image/equip/튠바디.jpg" alt="튠바디">
|
<img src="/image/equip/튠바디.jpg" alt="튠바디">
|
||||||
</div>
|
</div>
|
||||||
<div class="equipment-info">
|
<div class="equipment-info">
|
||||||
<h3 class="equipment-name">튠바디</h3>
|
<h3 class="equipment-name">튠바디</h3>
|
||||||
<p class="equipment-desc">깊은 탄력과 리프팅을 동시에</p>
|
<!-- <p class="equipment-desc">깊은 탄력과 리프팅을 동시에</p> -->
|
||||||
<p class="equipment-price"><!-- 150,000<span>부터</span> --></p>
|
<p class="equipment-price"><!-- 150,000<span>부터</span> --></p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -132,7 +139,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="equipment-info">
|
<div class="equipment-info">
|
||||||
<h3 class="equipment-name">튠페이스</h3>
|
<h3 class="equipment-name">튠페이스</h3>
|
||||||
<p class="equipment-desc">깊은 탄력과 리프팅을 동시에</p>
|
<!-- <p class="equipment-desc">깊은 탄력과 리프팅을 동시에</p> -->
|
||||||
<p class="equipment-price"><!-- 400,000<span>부터</span> --></p>
|
<p class="equipment-price"><!-- 400,000<span>부터</span> --></p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -143,7 +150,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="equipment-info">
|
<div class="equipment-info">
|
||||||
<h3 class="equipment-name">울핏</h3>
|
<h3 class="equipment-name">울핏</h3>
|
||||||
<p class="equipment-desc">깊은 탄력과 리프팅을 동시에</p>
|
<!-- <p class="equipment-desc">깊은 탄력과 리프팅을 동시에</p> -->
|
||||||
<p class="equipment-price"><!-- 50,000<span>부터</span> --></p>
|
<p class="equipment-price"><!-- 50,000<span>부터</span> --></p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -154,7 +161,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="equipment-info">
|
<div class="equipment-info">
|
||||||
<h3 class="equipment-name">포텐자</h3>
|
<h3 class="equipment-name">포텐자</h3>
|
||||||
<p class="equipment-desc">깊은 탄력과 리프팅을 동시에</p>
|
<!-- <p class="equipment-desc">깊은 탄력과 리프팅을 동시에</p> -->
|
||||||
<p class="equipment-price"><!-- 150,000<span>부터</span> --></p>
|
<p class="equipment-price"><!-- 150,000<span>부터</span> --></p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -165,7 +172,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="equipment-info">
|
<div class="equipment-info">
|
||||||
<h3 class="equipment-name">인모드</h3>
|
<h3 class="equipment-name">인모드</h3>
|
||||||
<p class="equipment-desc">깊은 탄력과 리프팅을 동시에</p>
|
<!-- <p class="equipment-desc">깊은 탄력과 리프팅을 동시에</p> -->
|
||||||
<p class="equipment-price"><!-- 100,000<span>부터</span> --></p>
|
<p class="equipment-price"><!-- 100,000<span>부터</span> --></p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -177,7 +184,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="equipment-info">
|
<div class="equipment-info">
|
||||||
<h3 class="equipment-name">슈링크유니버스</h3>
|
<h3 class="equipment-name">슈링크유니버스</h3>
|
||||||
<p class="equipment-desc">깊은 탄력과 리프팅을 동시에</p>
|
<!-- <p class="equipment-desc">깊은 탄력과 리프팅을 동시에</p> -->
|
||||||
<p class="equipment-price"><!-- 89,000<span>부터</span> --></p>
|
<p class="equipment-price"><!-- 89,000<span>부터</span> --></p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -188,7 +195,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="equipment-info">
|
<div class="equipment-info">
|
||||||
<h3 class="equipment-name">바디고주파테라피</h3>
|
<h3 class="equipment-name">바디고주파테라피</h3>
|
||||||
<p class="equipment-desc">깊은 탄력과 리프팅을 동시에</p>
|
<!-- <p class="equipment-desc">깊은 탄력과 리프팅을 동시에</p> -->
|
||||||
<p class="equipment-price"><!-- 100,000<span>부터</span> --></p>
|
<p class="equipment-price"><!-- 100,000<span>부터</span> --></p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -199,21 +206,12 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="equipment-info">
|
<div class="equipment-info">
|
||||||
<h3 class="equipment-name">리포덤</h3>
|
<h3 class="equipment-name">리포덤</h3>
|
||||||
<p class="equipment-desc">깊은 탄력과 리프팅을 동시에</p>
|
<!-- <p class="equipment-desc">깊은 탄력과 리프팅을 동시에</p> -->
|
||||||
<p class="equipment-price"><!-- 50,000<span>부터</span> --></p>
|
<p class="equipment-price"><!-- 50,000<span>부터</span> --></p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="equipment-card">
|
|
||||||
<div class="equipment-image">
|
|
||||||
<img src="/image/equip/라비앙.jpg" alt="라비앙">
|
|
||||||
</div>
|
|
||||||
<div class="equipment-info">
|
|
||||||
<h3 class="equipment-name">라비앙</h3>
|
|
||||||
<p class="equipment-desc">깊은 탄력과 리프팅을 동시에</p>
|
|
||||||
<p class="equipment-price"><!-- 165,000<span>부터</span> --></p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
@@ -246,7 +244,8 @@
|
|||||||
<li class="red_box">
|
<li class="red_box">
|
||||||
<div class="text_box">
|
<div class="text_box">
|
||||||
<p>
|
<p>
|
||||||
<span>고객을 가족으로 생각하는 마음으로<br class="pc"/>정직한 시술, <br class="mb"/>만족할 수 있는 결과,</span><br/>
|
<span>고객을 가족으로 생각하는 마음으로<br class="pc" />정직한 시술, <br class="mb" />만족할 수 있는
|
||||||
|
결과,</span><br />
|
||||||
더 나은 감동을 선사하기 위해<br />
|
더 나은 감동을 선사하기 위해<br />
|
||||||
끊임없이 노력하겠습니다.
|
끊임없이 노력하겠습니다.
|
||||||
</p>
|
</p>
|
||||||
@@ -287,4 +286,5 @@
|
|||||||
</th:block>
|
</th:block>
|
||||||
<th:block layout:fragment="layoutContentScript">
|
<th:block layout:fragment="layoutContentScript">
|
||||||
</th:block>
|
</th:block>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
@@ -34,9 +34,9 @@
|
|||||||
<li>
|
<li>
|
||||||
<img src="/image/web/profile1.jpg" alt="profile"/>
|
<img src="/image/web/profile1.jpg" alt="profile"/>
|
||||||
<div class="text_box">
|
<div class="text_box">
|
||||||
<p class="field">
|
<!--<p class="field">
|
||||||
<span>비만</span>
|
<span>비만</span>
|
||||||
</p>
|
</p>-->
|
||||||
<p class="name">
|
<p class="name">
|
||||||
<span class="name">박재우</span>
|
<span class="name">박재우</span>
|
||||||
대표원장 / <span>Chief Medical Director</span>
|
대표원장 / <span>Chief Medical Director</span>
|
||||||
@@ -45,14 +45,13 @@
|
|||||||
<span>Profile</span><br/>
|
<span>Profile</span><br/>
|
||||||
현) 메이드유의원 프랜차이즈 대표원장 <br/>
|
현) 메이드유의원 프랜차이즈 대표원장 <br/>
|
||||||
현) 메이드유의원 강남본점 대표원장 <br/>
|
현) 메이드유의원 강남본점 대표원장 <br/>
|
||||||
현) 메이드유의원 비만센터 대표원장 <br/>
|
|
||||||
대한미용외과학회 회원 <br/>
|
대한미용외과학회 회원 <br/>
|
||||||
대한미용성형레이저의학회 회원 <br/>
|
대한미용성형레이저의학회 회원 <br/>
|
||||||
대한비만치료학회 회원
|
대한비만치료학회 회원
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<!--<li>
|
||||||
<img src="/image/web/profile2.png" alt="profile"/>
|
<img src="/image/web/profile2.png" alt="profile"/>
|
||||||
<div class="text_box">
|
<div class="text_box">
|
||||||
<p class="field">
|
<p class="field">
|
||||||
@@ -74,7 +73,7 @@
|
|||||||
한국미용성형학회 회원
|
한국미용성형학회 회원
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>-->
|
||||||
<!-- <li> 2025.09.03 요구사항으로 인한 주석처리 byPJS
|
<!-- <li> 2025.09.03 요구사항으로 인한 주석처리 byPJS
|
||||||
<img src="/image/web/profile3.png" alt="profile"/>
|
<img src="/image/web/profile3.png" alt="profile"/>
|
||||||
<div class="text_box">
|
<div class="text_box">
|
||||||
@@ -98,7 +97,7 @@
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</li> -->
|
</li> -->
|
||||||
<li>
|
<!--<li>
|
||||||
<img src="/image/web/profile4.png" alt="profile"/>
|
<img src="/image/web/profile4.png" alt="profile"/>
|
||||||
<div class="text_box">
|
<div class="text_box">
|
||||||
<p class="field">
|
<p class="field">
|
||||||
@@ -120,7 +119,7 @@
|
|||||||
대한미용성형레이저의학회 회원
|
대한미용성형레이저의학회 회원
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>-->
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@@ -3,10 +3,21 @@
|
|||||||
xmlns:th="http://www.thymeleaf.org"
|
xmlns:th="http://www.thymeleaf.org"
|
||||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
|
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
|
||||||
<head>
|
<head>
|
||||||
|
<!-- Google Tag Manager -->
|
||||||
|
<script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
|
||||||
|
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
|
||||||
|
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
|
||||||
|
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
|
||||||
|
})(window,document,'script','dataLayer','GTM-N4SDGT5N');</script>
|
||||||
|
<!-- End Google Tag Manager -->
|
||||||
<th:block th:replace="/web/layout/layoutHead :: layoutHead"></th:block>
|
<th:block th:replace="/web/layout/layoutHead :: layoutHead"></th:block>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
<!-- Google Tag Manager (noscript) -->
|
||||||
|
<noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-N4SDGT5N"
|
||||||
|
height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
|
||||||
|
<!-- End Google Tag Manager (noscript) -->
|
||||||
<!-- 상단 스크립트 타임리프 변수 선언 -->
|
<!-- 상단 스크립트 타임리프 변수 선언 -->
|
||||||
<th:block layout:fragment="layout_top_script"></th:block>
|
<th:block layout:fragment="layout_top_script"></th:block>
|
||||||
|
|
||||||
|
|||||||
@@ -5,8 +5,7 @@
|
|||||||
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||||
<meta name="keyword" content="HTML, meta, tag, element, reference">
|
<meta name="keyword" content="HTML, meta, tag, element, reference">
|
||||||
<meta name="author" content="NTSOFT">
|
<meta name="author" content="VARASOFT">
|
||||||
<meta name="description" content={props.description} data-react-helmet="true" />
|
|
||||||
|
|
||||||
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
|
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
|
||||||
<meta http-equiv="Cache-Control" content="No-Cache" />
|
<meta http-equiv="Cache-Control" content="No-Cache" />
|
||||||
@@ -16,14 +15,13 @@
|
|||||||
<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE10">
|
<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE10">
|
||||||
|
|
||||||
<!-- sns미리보기 -->
|
<!-- sns미리보기 -->
|
||||||
|
<meta name="description" content="다이어트약, 강남피부과,비만클리닉, 리쥬란힐러,신논현피부과,논현피부과,스컬트라,울쎄라,강남울쎄라,써마지,강남써마지,지방분해주사,윤곽주사">
|
||||||
<meta property="og:type" content="website">
|
<meta property="og:type" content="website">
|
||||||
<!-- <meta property="og:url" content="https://ntsoft.kr/"> -->
|
<meta property="og:title" content="메이드유의원 강남본점">
|
||||||
<meta property="og:image" content="">
|
<meta name="og:description" content="다이어트약, 강남피부과,비만클리닉, 리쥬란힐러,신논현피부과,논현피부과,스컬트라,울쎄라,강남울쎄라,써마지,강남써마지,지방분해주사,윤곽주사">
|
||||||
<meta property="og:title" content="메이드유">
|
|
||||||
<meta property="og:description" content="설명문구">
|
|
||||||
|
|
||||||
<!-- 사이트등록및소유확인 -->
|
<!-- 사이트등록및소유확인 -->
|
||||||
<meta name="naver-site-verification" content="" />
|
<meta name="naver-site-verification" content="8720c03a4463520a0bd0979a3a743ff8ef0d8a03" />
|
||||||
|
|
||||||
<title>메이드유</title>
|
<title>메이드유</title>
|
||||||
|
|
||||||
|
|||||||
@@ -52,6 +52,12 @@
|
|||||||
quickMenu.style.display = '';
|
quickMenu.style.display = '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
function moveEvent() {
|
||||||
|
window.location.href = "https://petit.madeu.co.kr/webevent/selectListWebEventIntro.do";
|
||||||
|
}
|
||||||
|
function moveReview() {
|
||||||
|
window.location.href = "https://petit.madeu.co.kr/webreview/selectListProcedureReviewIntro.do";
|
||||||
|
}
|
||||||
|
|
||||||
// 페이지 로드와 리사이즈 이벤트 연결
|
// 페이지 로드와 리사이즈 이벤트 연결
|
||||||
window.addEventListener('load', toggleQuickMenu);
|
window.addEventListener('load', toggleQuickMenu);
|
||||||
@@ -79,7 +85,12 @@
|
|||||||
</header>
|
</header>
|
||||||
<!-- 퀵메뉴 -->
|
<!-- 퀵메뉴 -->
|
||||||
<div class="quick-menu-simple">
|
<div class="quick-menu-simple">
|
||||||
|
<div class="quick-item" onclick="moveReview()">
|
||||||
|
<img src="/image/quick_menu/review.png" alt="고객후기">
|
||||||
|
</div>
|
||||||
|
<div class="quick-item" onclick="moveEvent()">
|
||||||
|
<img src="/image/quick_menu/event.png" alt="이벤트">
|
||||||
|
</div>
|
||||||
<!-- 다이어트센터 -->
|
<!-- 다이어트센터 -->
|
||||||
<div class="quick-item" onclick="moveDietCenter()">
|
<div class="quick-item" onclick="moveDietCenter()">
|
||||||
<img src="/image/quick_menu/diet_center.png" alt="다이어트센터">
|
<img src="/image/quick_menu/diet_center.png" alt="다이어트센터">
|
||||||
@@ -102,4 +113,5 @@
|
|||||||
</div>
|
</div>
|
||||||
<script src="/js/web/layout/layoutHeader.js?ver=1"></script>
|
<script src="/js/web/layout/layoutHeader.js?ver=1"></script>
|
||||||
</th:block>
|
</th:block>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
@@ -28,8 +28,7 @@
|
|||||||
.container {
|
.container {
|
||||||
max-width: 1280px;
|
max-width: 1280px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: calc(100vh - 300px); /* 헤더/푸터 공간 확보 */
|
height: 100vh; /* 헤더/푸터 공간 확보 */
|
||||||
min-height: calc(100vh - 300px);
|
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|||||||
@@ -1,423 +1,12 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html xmlns="http://www.w3.org/1999/xhtml"
|
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
|
||||||
xmlns:th="http://www.thymeleaf.org"
|
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{/web/layout/layout}">
|
||||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
|
||||||
layout:decorate="~{/web/layout/layout}">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
|
||||||
<th:block layout:fragment="layoutCss">
|
<th:block layout:fragment="layoutCss">
|
||||||
<!-- Choices.js CSS -->
|
<!-- Choices.js CSS -->
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/choices.js/10.2.0/choices.min.css" />
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/choices.js/10.2.0/choices.min.css" />
|
||||||
|
<link rel="stylesheet" th:href="@{/css/web/webevent/webEventSelect.css}" />
|
||||||
<style>
|
|
||||||
* { box-sizing: border-box; }
|
|
||||||
body {
|
|
||||||
font-family: 'Noto Sans KR', sans-serif;
|
|
||||||
margin: 0;
|
|
||||||
background: #f7f7f9;
|
|
||||||
color: #222;
|
|
||||||
}
|
|
||||||
#service-header {
|
|
||||||
background: #fff;
|
|
||||||
border-bottom: 1px solid #ececec;
|
|
||||||
padding: 14px 0 14px 24px;
|
|
||||||
font-size: 0.98em;
|
|
||||||
color: #888;
|
|
||||||
}
|
|
||||||
.main-wrap {
|
|
||||||
max-width: 1280px;
|
|
||||||
margin: 0 auto;
|
|
||||||
background: #fff;
|
|
||||||
border-radius: 18px;
|
|
||||||
box-shadow: 0 2px 12px rgba(0,0,0,0.07);
|
|
||||||
margin-top: 32px;
|
|
||||||
padding: 0 0 32px 0;
|
|
||||||
}
|
|
||||||
.top-section {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
gap: 32px;
|
|
||||||
padding: 32px 32px 0 32px;
|
|
||||||
align-items: flex-start;
|
|
||||||
}
|
|
||||||
.img-box {
|
|
||||||
border-radius: 18px;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
.img-box img {
|
|
||||||
width: 100%;
|
|
||||||
object-fit: cover;
|
|
||||||
border-radius: 18px;
|
|
||||||
}
|
|
||||||
.info-box {
|
|
||||||
flex: 1 1 300px;
|
|
||||||
min-width: 240px;
|
|
||||||
}
|
|
||||||
.info-title {
|
|
||||||
font-size: 1.7em;
|
|
||||||
font-weight: 700;
|
|
||||||
margin-bottom: 6px;
|
|
||||||
color: #222;
|
|
||||||
}
|
|
||||||
.info-desc {
|
|
||||||
color: #444;
|
|
||||||
font-size: 1.1em;
|
|
||||||
margin-bottom: 18px;
|
|
||||||
}
|
|
||||||
.info-price {
|
|
||||||
font-size: 1.2em;
|
|
||||||
font-weight: 700;
|
|
||||||
color: #b23c3c;
|
|
||||||
margin-bottom: 18px;
|
|
||||||
}
|
|
||||||
.select-row {
|
|
||||||
margin-bottom: 18px;
|
|
||||||
}
|
|
||||||
.select-row label {
|
|
||||||
font-weight: 500;
|
|
||||||
margin-bottom: 8px;
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
.total-row {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
font-size: 1.1em;
|
|
||||||
margin-bottom: 18px;
|
|
||||||
}
|
|
||||||
.total-row .total-label {
|
|
||||||
color: #888;
|
|
||||||
}
|
|
||||||
.total-row .total-price {
|
|
||||||
font-weight: bold;
|
|
||||||
color: #b23c3c;
|
|
||||||
}
|
|
||||||
.reserve-btn {
|
|
||||||
width: 100%;
|
|
||||||
padding: 14px 0;
|
|
||||||
background: #b23c3c;
|
|
||||||
color: #fff;
|
|
||||||
border: none;
|
|
||||||
border-radius: 8px;
|
|
||||||
font-size: 1.1em;
|
|
||||||
font-weight: bold;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: background 0.15s;
|
|
||||||
}
|
|
||||||
.reserve-btn:disabled {
|
|
||||||
background: #ddd;
|
|
||||||
color: #888;
|
|
||||||
cursor: not-allowed;
|
|
||||||
}
|
|
||||||
.desc-section {
|
|
||||||
margin-top: 36px;
|
|
||||||
padding: 0 32px;
|
|
||||||
}
|
|
||||||
.desc-title {
|
|
||||||
font-size: 1.25em;
|
|
||||||
font-weight: 700;
|
|
||||||
margin-bottom: 12px;
|
|
||||||
color: #222;
|
|
||||||
}
|
|
||||||
.desc-content {
|
|
||||||
color: #444;
|
|
||||||
font-size: 1.05em;
|
|
||||||
line-height: 1.7;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
}
|
|
||||||
.hashtag-section {
|
|
||||||
margin-top: 30px;
|
|
||||||
padding: 20px 0;
|
|
||||||
border-top: 1px solid #eee;
|
|
||||||
}
|
|
||||||
.hashtag-container {
|
|
||||||
max-width: 1200px;
|
|
||||||
margin: 0 auto;
|
|
||||||
padding: 0 20px;
|
|
||||||
}
|
|
||||||
.hashtag-list {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
gap: 10px;
|
|
||||||
}
|
|
||||||
.hashtag {
|
|
||||||
display: inline-block;
|
|
||||||
background-color: #f8f9fa;
|
|
||||||
color: #495057;
|
|
||||||
padding: 8px 15px;
|
|
||||||
border-radius: 20px;
|
|
||||||
font-size: 14px;
|
|
||||||
text-decoration: none;
|
|
||||||
border: 1px solid #dee2e6;
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
}
|
|
||||||
.hashtag:hover {
|
|
||||||
background-color: #007bff;
|
|
||||||
color: white;
|
|
||||||
border-color: #007bff;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
#thumbnail-bottom-txt{
|
|
||||||
padding: 8px;
|
|
||||||
margin-top: 10px;
|
|
||||||
background-color: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Choices.js 커스터마이징 - 개선된 버전 */
|
|
||||||
.choices {
|
|
||||||
border: 1px solid #ddd !important;
|
|
||||||
border-radius: 6px !important;
|
|
||||||
font-size: 1em !important;
|
|
||||||
background: #fff !important;
|
|
||||||
min-width: 300px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.choices__inner {
|
|
||||||
background: #fff !important;
|
|
||||||
padding: 8px 12px !important;
|
|
||||||
min-height: 40px !important;
|
|
||||||
color: #222 !important;
|
|
||||||
min-width: 280px !important;
|
|
||||||
width: 100% !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 플레이스홀더 텍스트 잘림 방지 - 핵심 수정 */
|
|
||||||
.choices__placeholder {
|
|
||||||
color: #888 !important;
|
|
||||||
opacity: 1 !important;
|
|
||||||
width: 100% !important;
|
|
||||||
min-width: 200px !important;
|
|
||||||
white-space: nowrap !important;
|
|
||||||
overflow: visible !important;
|
|
||||||
text-overflow: clip !important;
|
|
||||||
display: block !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.choices__input {
|
|
||||||
color: #222 !important;
|
|
||||||
background: transparent !important;
|
|
||||||
min-width: 200px !important;
|
|
||||||
width: 100% !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.choices__input::placeholder {
|
|
||||||
color: #888 !important;
|
|
||||||
opacity: 1 !important;
|
|
||||||
width: 100% !important;
|
|
||||||
min-width: 200px !important;
|
|
||||||
white-space: nowrap !important;
|
|
||||||
overflow: visible !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 다중 선택시 입력 필드 너비 확보 */
|
|
||||||
.choices[data-type*="select-multiple"] .choices__input {
|
|
||||||
min-width: 200px !important;
|
|
||||||
width: auto !important;
|
|
||||||
flex: 1 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 선택된 항목들과 입력 필드 공간 분배 */
|
|
||||||
.choices__list--multiple {
|
|
||||||
/* display: flex !important; */
|
|
||||||
flex-wrap: wrap !important;
|
|
||||||
align-items: center !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.choices__list--multiple:empty + .choices__input {
|
|
||||||
min-width: 200px !important;
|
|
||||||
width: 100% !important;
|
|
||||||
flex: 1 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 선택된 항목의 가격 표시 스타일 - 새로 추가 */
|
|
||||||
.selected-item-content {
|
|
||||||
display: flex !important;
|
|
||||||
flex-direction: column !important;
|
|
||||||
align-items: flex-start !important;
|
|
||||||
flex: 1 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.selected-item-name {
|
|
||||||
font-weight: 500 !important;
|
|
||||||
margin-bottom: 2px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.selected-item-price {
|
|
||||||
font-size: 0.85em !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.selected-price {
|
|
||||||
color: #b23c3c !important;
|
|
||||||
font-weight: bold !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.selected-price-discount {
|
|
||||||
color: #b23c3c !important;
|
|
||||||
font-weight: bold !important;
|
|
||||||
font-size: 0.9em !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.selected-price-original {
|
|
||||||
color: #aaa !important;
|
|
||||||
font-size: 0.85em !important;
|
|
||||||
text-decoration: line-through !important;
|
|
||||||
margin-left: 4px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 선택된 항목들 스타일 수정 */
|
|
||||||
.choices__list--multiple .choices__item {
|
|
||||||
background-color: #f8f9fa !important;
|
|
||||||
border: 1px solid #dee2e6 !important;
|
|
||||||
border-radius: 16px !important;
|
|
||||||
padding: 8px 12px !important;
|
|
||||||
margin: 2px !important;
|
|
||||||
font-size: 0.9em !important;
|
|
||||||
color: #495057 !important;
|
|
||||||
flex-shrink: 0 !important;
|
|
||||||
display: flex !important;
|
|
||||||
align-items: center !important;
|
|
||||||
/* max-width: 300px !important; */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 빨간색으로 변경 */
|
|
||||||
.choices__button {
|
|
||||||
background-image: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjEiIGhlaWdodD0iMjEiIHZpZXdCb3g9IjAgMCAyMSAyMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48ZyBmaWxsPSIjYjIzYzNjIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiPjxwYXRoIGQ9Ik0yLjU5Mi4wNDRsMTguMzY0IDE4LjM2NC0yLjU0OCAyLjU0OEwuMDQ0IDIuNTkyeiIvPjxwYXRoIGQ9Ik0wIDE4LjM2NEwxOC4zNjQgMGwyLjU0OCAyLjU0OEwyLjU0OCAyMC45MTJ6Ii8+PC9nPjwvc3ZnPg==') !important;
|
|
||||||
background-size: 14px 14px !important;
|
|
||||||
background-position: center !important;
|
|
||||||
background-repeat: no-repeat !important;
|
|
||||||
border-left:0 !important;
|
|
||||||
margin:0 !important;
|
|
||||||
padding:0 !important;
|
|
||||||
width:14px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 드롭다운 컨테이너 */
|
|
||||||
.choices__list--dropdown {
|
|
||||||
background: #fff !important;
|
|
||||||
border: 1px solid #ddd !important;
|
|
||||||
border-radius: 6px !important;
|
|
||||||
box-shadow: 0 2px 8px rgba(0,0,0,0.1) !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 드롭다운 옵션들 스타일 */
|
|
||||||
.choices__list--dropdown .choices__item {
|
|
||||||
padding: 8px 12px !important;
|
|
||||||
display: flex !important;
|
|
||||||
justify-content: space-between !important;
|
|
||||||
align-items: center !important;
|
|
||||||
color: #222 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.choices__list--dropdown .choices__item--selectable:hover {
|
|
||||||
background-color: #f5f5f5 !important;
|
|
||||||
color: #222 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.choices__list--dropdown .choices__item--highlighted {
|
|
||||||
background-color: #b23c3c !important;
|
|
||||||
color: #fff !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 포커스 상태 */
|
|
||||||
.choices.is-focused .choices__inner {
|
|
||||||
border-color: #b23c3c !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 가격 표시 스타일 */
|
|
||||||
.procedure-price {
|
|
||||||
color: #b23c3c !important;
|
|
||||||
font-weight: bold !important;
|
|
||||||
font-size: 0.9em !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.procedure-price-discount {
|
|
||||||
color: #b23c3c !important;
|
|
||||||
font-weight: bold !important;
|
|
||||||
font-size: 0.9em !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.procedure-price-original {
|
|
||||||
color: #aaa !important;
|
|
||||||
font-size: 0.85em !important;
|
|
||||||
text-decoration: line-through !important;
|
|
||||||
margin-left: 4px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 드롭다운이 열렸을 때 하이라이트된 항목의 가격 색상 */
|
|
||||||
.choices__list--dropdown .choices__item--highlighted .procedure-price,
|
|
||||||
.choices__list--dropdown .choices__item--highlighted .procedure-price-discount {
|
|
||||||
color: #fff !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.choices__list--dropdown .choices__item--highlighted .procedure-price-original {
|
|
||||||
color: #ddd !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 검색 입력창 스타일 */
|
|
||||||
.choices[data-type*="select-multiple"] .choices__input {
|
|
||||||
background-color: transparent !important;
|
|
||||||
color: #222 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 비활성화 상태 */
|
|
||||||
.choices.is-disabled .choices__inner {
|
|
||||||
background-color: #f8f9fa !important;
|
|
||||||
color: #6c757d !important;
|
|
||||||
cursor: not-allowed !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 반응형 대응 */
|
|
||||||
@media (max-width: 600px) {
|
|
||||||
.choices {
|
|
||||||
min-width: 250px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.choices__inner {
|
|
||||||
min-width: 230px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.choices__placeholder,
|
|
||||||
.choices__input,
|
|
||||||
.choices__input::placeholder {
|
|
||||||
min-width: 150px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.choices__list--multiple .choices__item {
|
|
||||||
max-width: 250px !important;
|
|
||||||
padding: 6px 10px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.selected-item-name {
|
|
||||||
font-size: 0.9em !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.selected-item-price {
|
|
||||||
font-size: 0.8em !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.choices__list--multiple .choices__item[data-deletable] .choices__button {
|
|
||||||
width: 20px !important;
|
|
||||||
height: 20px !important;
|
|
||||||
font-size: 16px !important;
|
|
||||||
text-indent: 0 !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 900px) {
|
|
||||||
.main-wrap { margin-top: 16px; }
|
|
||||||
.top-section { flex-direction: column; gap: 18px; padding: 20px 10px 0 10px; }
|
|
||||||
.img-box { width: 100%;}
|
|
||||||
.info-box { min-width: unset; }
|
|
||||||
.desc-section { padding: 0 10px; }
|
|
||||||
}
|
|
||||||
@media (max-width: 600px) {
|
|
||||||
.main-wrap { margin-top: 0; border-radius: 0; box-shadow: none; }
|
|
||||||
.top-section { padding: 12px 2vw 0 2vw; }
|
|
||||||
.desc-section { padding: 0 2vw; }
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</th:block>
|
</th:block>
|
||||||
|
|
||||||
<th:block layout:fragment="layout_top_script">
|
<th:block layout:fragment="layout_top_script">
|
||||||
@@ -459,6 +48,8 @@ const CDN_URL = [[${@environment.getProperty('url.cdn')}]];
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="event-period" id="event-period" style="display:none;"></div>
|
||||||
|
|
||||||
<div class="info-price"><span id="price">0</span>원 부터</div>
|
<div class="info-price"><span id="price">0</span>원 부터</div>
|
||||||
|
|
||||||
<div class="select-row">
|
<div class="select-row">
|
||||||
@@ -484,299 +75,7 @@ const CDN_URL = [[${@environment.getProperty('url.cdn')}]];
|
|||||||
<th:block layout:fragment="layoutContentScript">
|
<th:block layout:fragment="layoutContentScript">
|
||||||
<!-- Choices.js JavaScript -->
|
<!-- Choices.js JavaScript -->
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/choices.js/10.2.0/choices.min.js"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/choices.js/10.2.0/choices.min.js"></script>
|
||||||
|
<script th:src="@{/js/web/webevent/webEventSelect.js}"></script>
|
||||||
<script>
|
|
||||||
// 전역 변수
|
|
||||||
let procedureChoices;
|
|
||||||
let priceList = [];
|
|
||||||
const totalEl = document.getElementById('total');
|
|
||||||
const reserveBtn = document.getElementById('reserve-btn');
|
|
||||||
|
|
||||||
// 초기화
|
|
||||||
fn_SelectDetail(category_div_cd, category_no, post_no);
|
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
* 카테고리 목록 가져오기
|
|
||||||
****************************************************************************/
|
|
||||||
function fn_SelectDetail(category_div_cd, category_no, post_no) {
|
|
||||||
let formData = new FormData();
|
|
||||||
formData.append('CATEGORY_DIV_CD', category_div_cd);
|
|
||||||
formData.append('CATEGORY_NO', category_no);
|
|
||||||
formData.append('POST_NO', post_no);
|
|
||||||
|
|
||||||
$.ajax({
|
|
||||||
url: encodeURI('/webevent/selectEventDetail.do'),
|
|
||||||
data: formData,
|
|
||||||
dataType: 'json',
|
|
||||||
processData: false,
|
|
||||||
contentType: false,
|
|
||||||
type: 'POST',
|
|
||||||
async: true,
|
|
||||||
success: function(data) {
|
|
||||||
if(data.msgCode == '0') {
|
|
||||||
// 화면 데이터 변경
|
|
||||||
$('#title').text(data.rows.TITLE);
|
|
||||||
$('#serviceThumb').attr('src', CDN_URL + data.rows.THUMBNAIL_PATH);
|
|
||||||
$('#thumbnail-bottom-txt').text(data.rows.THUMBNAIL_BOTTOM_TXT);
|
|
||||||
$('#contents').text(data.rows.CONTENT);
|
|
||||||
|
|
||||||
if(data.rows.PRICE == null || data.rows.PRICE == undefined) {
|
|
||||||
$('#price').text('0');
|
|
||||||
} else {
|
|
||||||
$('#price').text(data.rows.PRICE.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","));
|
|
||||||
}
|
|
||||||
|
|
||||||
// header 동적 변경
|
|
||||||
$('#header-category-nm').text(data.rows.CATEGORY_NM);
|
|
||||||
$('#header-title').text(data.rows.TITLE);
|
|
||||||
|
|
||||||
// 해시태그 처리
|
|
||||||
var hashtagHtml = '';
|
|
||||||
if (data.rows.HASHTAG) {
|
|
||||||
var tags = data.rows.HASHTAG.split('#');
|
|
||||||
tags.forEach(function(tag) {
|
|
||||||
var trimmed = tag.trim();
|
|
||||||
if(trimmed) {
|
|
||||||
hashtagHtml += '<span class="hashtag">#' + trimmed + '</span>';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
$('.hashtag-list').html(hashtagHtml);
|
|
||||||
|
|
||||||
$('#contents_path').attr('src', CDN_URL + data.rows.CONTENTS_PATH);
|
|
||||||
|
|
||||||
// 시술 목록 데이터 처리
|
|
||||||
updateProcedureOptions(data.price || []);
|
|
||||||
} else {
|
|
||||||
modalEvent.danger("조회 오류", data.msgDesc);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
error: function(xhr, status, error) {
|
|
||||||
modalEvent.danger("조회 오류", "조회 중 오류가 발생하였습니다. 잠시후 다시시도하십시오.");
|
|
||||||
},
|
|
||||||
beforeSend: function() {
|
|
||||||
$(".loading-image-layer").show();
|
|
||||||
},
|
|
||||||
complete: function() {
|
|
||||||
$(".loading-image-layer").hide();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
* Choices.js 초기화 및 옵션 업데이트
|
|
||||||
****************************************************************************/
|
|
||||||
function updateProcedureOptions(data) {
|
|
||||||
priceList = data;
|
|
||||||
|
|
||||||
// 기존 Choices 인스턴스 제거
|
|
||||||
if (procedureChoices) {
|
|
||||||
procedureChoices.destroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 선택 옵션 데이터 생성
|
|
||||||
const choices = data.map(item => {
|
|
||||||
if (!item.MU_TREATMENT_PROCEDURE_ID || !item.TREATMENT_PROCEDURE_NAME) return null;
|
|
||||||
|
|
||||||
const basePrice = (item.PRICE || 0) + (item.VAT || 0);
|
|
||||||
const discountPrice = item.DISCOUNT_PRICE;
|
|
||||||
|
|
||||||
return {
|
|
||||||
value: item.MU_TREATMENT_PROCEDURE_ID,
|
|
||||||
label: item.TREATMENT_PROCEDURE_NAME,
|
|
||||||
customProperties: {
|
|
||||||
name: item.TREATMENT_PROCEDURE_NAME,
|
|
||||||
price: basePrice,
|
|
||||||
discountPrice: discountPrice,
|
|
||||||
originalData: item
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}).filter(Boolean);
|
|
||||||
|
|
||||||
// Choices.js 초기화
|
|
||||||
procedureChoices = new Choices('#procedure-select', {
|
|
||||||
removeItemButton: true,
|
|
||||||
searchEnabled: true,
|
|
||||||
searchPlaceholderValue: '시술명으로 검색...',
|
|
||||||
placeholder: true,
|
|
||||||
placeholderValue: '시술을 선택하세요',
|
|
||||||
maxItemCount: -1,
|
|
||||||
choices: choices,
|
|
||||||
shouldSort: false,
|
|
||||||
searchResultLimit: 10,
|
|
||||||
searchFields: ['label', 'value'],
|
|
||||||
itemSelectText: '',
|
|
||||||
noChoicesText: '선택 가능한 시술이 없습니다',
|
|
||||||
noResultsText: '검색 결과가 없습니다',
|
|
||||||
loadingText: '시술 정보를 불러오는 중...',
|
|
||||||
|
|
||||||
// 템플릿 커스터마이징 - 선택된 항목에 가격 표시 추가
|
|
||||||
callbackOnCreateTemplates: function(template) {
|
|
||||||
return {
|
|
||||||
// 선택된 항목 템플릿 - 가격 정보 포함
|
|
||||||
item: ({ classNames }, data) => {
|
|
||||||
const customProps = data.customProperties || {};
|
|
||||||
const name = customProps.name || data.label;
|
|
||||||
const price = customProps.price || 0;
|
|
||||||
const discountPrice = customProps.discountPrice;
|
|
||||||
|
|
||||||
// 가격 표시 HTML 생성
|
|
||||||
let priceHtml = '';
|
|
||||||
if (discountPrice && discountPrice < price) {
|
|
||||||
priceHtml = `
|
|
||||||
<span class="selected-price-discount">${discountPrice.toLocaleString()}원</span>
|
|
||||||
<span class="selected-price-original">${price.toLocaleString()}원</span>
|
|
||||||
`;
|
|
||||||
} else {
|
|
||||||
priceHtml = `<span class="selected-price">${price.toLocaleString()}원</span>`;
|
|
||||||
}
|
|
||||||
|
|
||||||
return template(`
|
|
||||||
<div class="${classNames.item} ${data.highlighted ? classNames.highlightedState : classNames.itemSelectable}" data-item data-id="${data.id}" data-value="${data.value}">
|
|
||||||
<span class="selected-item-content">
|
|
||||||
<span class="selected-item-name">${name}</span>
|
|
||||||
<span class="selected-item-price">${priceHtml}</span>
|
|
||||||
</span>
|
|
||||||
<button type="button" class="${classNames.button}" aria-label="Remove item: '${data.value}'" data-button>X</button>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
`);
|
|
||||||
},
|
|
||||||
|
|
||||||
// 드롭다운 선택 옵션 템플릿
|
|
||||||
choice: ({ classNames }, data) => {
|
|
||||||
const customProps = data.customProperties || {};
|
|
||||||
const name = customProps.name || data.label;
|
|
||||||
const price = customProps.price || 0;
|
|
||||||
const discountPrice = customProps.discountPrice;
|
|
||||||
|
|
||||||
let priceHtml = '';
|
|
||||||
if (discountPrice && discountPrice < price) {
|
|
||||||
priceHtml = `
|
|
||||||
<span class="procedure-price-discount">${discountPrice.toLocaleString()}원</span>
|
|
||||||
<span class="procedure-price-original">${price.toLocaleString()}원</span>
|
|
||||||
`;
|
|
||||||
} else {
|
|
||||||
priceHtml = `<span class="procedure-price">${price.toLocaleString()}원</span>`;
|
|
||||||
}
|
|
||||||
|
|
||||||
return template(`
|
|
||||||
<div class="${classNames.item} ${classNames.itemChoice} ${data.disabled ? classNames.itemDisabled : classNames.itemSelectable}" data-select-text="" data-choice ${data.disabled ? 'data-choice-disabled aria-disabled="true"' : 'data-choice-selectable'} data-id="${data.id}" data-value="${data.value}">
|
|
||||||
<div style="display: flex; justify-content: space-between; width: 100%; align-items: center;">
|
|
||||||
<span>${name}</span>
|
|
||||||
${priceHtml}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
`);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// 이벤트 리스너 추가
|
|
||||||
const selectElement = document.getElementById('procedure-select');
|
|
||||||
selectElement.addEventListener('change', function(event) {
|
|
||||||
console.log('Selection changed:', event.detail);
|
|
||||||
updateTotalPrice();
|
|
||||||
});
|
|
||||||
|
|
||||||
selectElement.addEventListener('addItem', function(event) {
|
|
||||||
console.log('Item added:', event.detail);
|
|
||||||
updateTotalPrice();
|
|
||||||
});
|
|
||||||
|
|
||||||
selectElement.addEventListener('removeItem', function(event) {
|
|
||||||
console.log('Item removed:', event.detail);
|
|
||||||
updateTotalPrice();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
* 총 금액 업데이트 - 개선된 버전
|
|
||||||
****************************************************************************/
|
|
||||||
function updateTotalPrice() {
|
|
||||||
if (!procedureChoices) {
|
|
||||||
console.log('procedureChoices not initialized');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const selectedValues = procedureChoices.getValue(true);
|
|
||||||
console.log('Selected values:', selectedValues);
|
|
||||||
|
|
||||||
let total = 0;
|
|
||||||
|
|
||||||
selectedValues.forEach(value => {
|
|
||||||
const item = priceList.find(p => p.MU_TREATMENT_PROCEDURE_ID == value);
|
|
||||||
console.log('Found item for value', value, ':', item);
|
|
||||||
|
|
||||||
if (item) {
|
|
||||||
const basePrice = (item.PRICE || 0) + (item.VAT || 0);
|
|
||||||
const discountPrice = item.DISCOUNT_PRICE;
|
|
||||||
|
|
||||||
// 할인가가 있고 더 저렴하면 할인가 사용, 아니면 기본가격 사용
|
|
||||||
const finalPrice = (discountPrice && discountPrice < basePrice) ? discountPrice : basePrice;
|
|
||||||
total += finalPrice;
|
|
||||||
console.log('Added price:', finalPrice);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log('Total calculated:', total);
|
|
||||||
totalEl.textContent = total.toLocaleString() + '원';
|
|
||||||
reserveBtn.disabled = selectedValues.length === 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
* 예약 페이지로 이동
|
|
||||||
****************************************************************************/
|
|
||||||
function fn_moveReservation(category_div, category_no, post_no) {
|
|
||||||
if (!procedureChoices) {
|
|
||||||
alert('시술 선택 기능이 초기화되지 않았습니다.');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const selectedValues = procedureChoices.getValue(true);
|
|
||||||
|
|
||||||
if (selectedValues.length === 0) {
|
|
||||||
alert('시술을 선택해주세요.');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const form = document.createElement('form');
|
|
||||||
form.method = 'post';
|
|
||||||
form.action = '/webevent/selectMakeReservation.do';
|
|
||||||
|
|
||||||
// 기본 파라미터 추가
|
|
||||||
const params = [
|
|
||||||
{ name: 'CATEGORY_DIV_CD', value: category_div },
|
|
||||||
{ name: 'CATEGORY_NO', value: category_no },
|
|
||||||
{ name: 'POST_NO', value: post_no }
|
|
||||||
];
|
|
||||||
|
|
||||||
params.forEach(param => {
|
|
||||||
const input = document.createElement('input');
|
|
||||||
input.type = 'hidden';
|
|
||||||
input.name = param.name;
|
|
||||||
input.value = param.value;
|
|
||||||
form.appendChild(input);
|
|
||||||
});
|
|
||||||
|
|
||||||
// 선택된 시술 추가
|
|
||||||
selectedValues.forEach(value => {
|
|
||||||
const input = document.createElement('input');
|
|
||||||
input.type = 'hidden';
|
|
||||||
input.name = 'PROCEDURE_ID';
|
|
||||||
input.value = value;
|
|
||||||
form.appendChild(input);
|
|
||||||
});
|
|
||||||
|
|
||||||
document.body.appendChild(form);
|
|
||||||
form.submit();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 예약 버튼 이벤트
|
|
||||||
reserveBtn.addEventListener('click', function() {
|
|
||||||
fn_moveReservation(category_div_cd, category_no, post_no);
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
</th:block>
|
</th:block>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
@@ -1,397 +1,8 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html xmlns="http://www.w3.org/1999/xhtml"
|
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
|
||||||
xmlns:th="http://www.thymeleaf.org"
|
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{/web/layout/layout}">
|
||||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
|
||||||
layout:decorate="~{/web/layout/layout}">
|
|
||||||
<th:block layout:fragment="layoutCss">
|
<th:block layout:fragment="layoutCss">
|
||||||
<style>
|
<link rel="stylesheet" th:href="@{/css/web/webevent/webEventSelectList.css}" />
|
||||||
* {
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 전체 기본 스타일 */
|
|
||||||
html, body {
|
|
||||||
height: 100vh;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
font-family: 'Pretendard', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', sans-serif;
|
|
||||||
background: #f8f9fa;
|
|
||||||
color: #1a1a1a;
|
|
||||||
overflow-x: hidden;
|
|
||||||
font-size: 16px;
|
|
||||||
line-height: 1.6;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 메인 컨테이너 */
|
|
||||||
.container {
|
|
||||||
max-width: 1280px;
|
|
||||||
width: 100%;
|
|
||||||
margin: 0 auto;
|
|
||||||
min-height: calc(100vh - 300px);
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 1.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 상단 헤더 영역 */
|
|
||||||
.header {
|
|
||||||
background: white;
|
|
||||||
border-radius: 16px;
|
|
||||||
box-shadow: 0 2px 16px rgba(0,0,0,0.06);
|
|
||||||
padding: 1rem 2rem;
|
|
||||||
border-bottom: 3px solid #C60B24;
|
|
||||||
flex-shrink: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.page-title {
|
|
||||||
font-size: clamp(1.5rem, 3vw, 1.875rem); /* 24px ~ 30px */
|
|
||||||
font-weight: 700;
|
|
||||||
color: #1a1a1a;
|
|
||||||
margin: 0;
|
|
||||||
letter-spacing: -0.025em;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 하단 콘텐츠 영역 (사이드바 + 메인) */
|
|
||||||
.content-wrapper {
|
|
||||||
flex: 1;
|
|
||||||
display: flex;
|
|
||||||
gap: 1.5rem;
|
|
||||||
min-height: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 좌측 사이드바 */
|
|
||||||
.sidebar {
|
|
||||||
width: 240px;
|
|
||||||
min-width: 220px;
|
|
||||||
flex-shrink: 0;
|
|
||||||
background: white;
|
|
||||||
border-radius: 16px;
|
|
||||||
box-shadow: 0 2px 16px rgba(0,0,0,0.06);
|
|
||||||
height: fit-content;
|
|
||||||
max-height: 100%;
|
|
||||||
overflow-y: auto;
|
|
||||||
position: sticky;
|
|
||||||
top: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar-header {
|
|
||||||
padding: 1.25rem 1.5rem;
|
|
||||||
font-size: 1.125rem; /* 18px */
|
|
||||||
font-weight: 700;
|
|
||||||
color: #C60B24;
|
|
||||||
border-bottom: 1px solid #e9ecef;
|
|
||||||
}
|
|
||||||
|
|
||||||
.category-list {
|
|
||||||
list-style: none;
|
|
||||||
padding: 1rem;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.category-item {
|
|
||||||
margin-bottom: 0.375rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.category-link {
|
|
||||||
display: block;
|
|
||||||
width: 100%;
|
|
||||||
padding: 0.75rem 1rem;
|
|
||||||
font-size: 0.95rem; /* 15.2px */
|
|
||||||
color: #6b7280;
|
|
||||||
text-decoration: none;
|
|
||||||
background: none;
|
|
||||||
border: none;
|
|
||||||
border-radius: 10px;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: all 0.2s ease;
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
.category-link:hover {
|
|
||||||
background: #f9fafb;
|
|
||||||
color: #C60B24;
|
|
||||||
transform: translateX(2px);
|
|
||||||
}
|
|
||||||
|
|
||||||
.category-link.active {
|
|
||||||
background: rgba(198, 11, 36, 0.08);
|
|
||||||
color: #C60B24;
|
|
||||||
font-weight: 600;
|
|
||||||
border-left: 4px solid #C60B24;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 메인 콘텐츠 영역 */
|
|
||||||
.main-content {
|
|
||||||
flex: 1;
|
|
||||||
min-width: 0;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 이벤트 리스트 */
|
|
||||||
.event-list {
|
|
||||||
flex: 1;
|
|
||||||
overflow-y: auto;
|
|
||||||
padding-right: 0.5rem;
|
|
||||||
min-height: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.event-grid {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 1.25rem;
|
|
||||||
padding-bottom: 2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 이벤트 카드 */
|
|
||||||
.event-card {
|
|
||||||
display: flex;
|
|
||||||
background: white;
|
|
||||||
border-radius: 16px;
|
|
||||||
box-shadow: 0 2px 16px rgba(0,0,0,0.06);
|
|
||||||
overflow: hidden;
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
border: 1px solid #f1f5f9;
|
|
||||||
min-height: 160px;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.event-card:hover {
|
|
||||||
transform: translateY(-4px);
|
|
||||||
box-shadow: 0 8px 32px rgba(0,0,0,0.12);
|
|
||||||
border-color: #C60B24;
|
|
||||||
}
|
|
||||||
|
|
||||||
.event-img {
|
|
||||||
width: 340px;
|
|
||||||
min-width: 280px;
|
|
||||||
background: #f3f4f6;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.event-img img {
|
|
||||||
width: 100%;
|
|
||||||
object-fit: cover;
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.event-info {
|
|
||||||
flex: 1;
|
|
||||||
padding: 1.5rem;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: space-between;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.event-title {
|
|
||||||
font-size: 1.25rem; /* 20px */
|
|
||||||
font-weight: 700;
|
|
||||||
margin-bottom: 0.5rem;
|
|
||||||
color: #1a1a1a;
|
|
||||||
letter-spacing: -0.025em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.event-desc {
|
|
||||||
color: #6b7280;
|
|
||||||
font-size: 0.9375rem; /* 15px */
|
|
||||||
margin-bottom: 0.75rem;
|
|
||||||
line-height: 1.5;
|
|
||||||
}
|
|
||||||
|
|
||||||
.event-meta {
|
|
||||||
font-size: 0.875rem; /* 14px */
|
|
||||||
color: #9ca3af;
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.event-price {
|
|
||||||
font-size: 1.125rem; /* 18px */
|
|
||||||
color: #C60B24;
|
|
||||||
font-weight: 700;
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 로딩 및 에러 메시지 */
|
|
||||||
.loading {
|
|
||||||
text-align: center;
|
|
||||||
padding: 2rem;
|
|
||||||
color: #6b7280;
|
|
||||||
font-size: 0.9375rem; /* 15px */
|
|
||||||
}
|
|
||||||
|
|
||||||
.error-message {
|
|
||||||
text-align: center;
|
|
||||||
padding: 2rem;
|
|
||||||
color: #dc2626;
|
|
||||||
font-size: 0.9375rem; /* 15px */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 스크롤바 커스터마이징 */
|
|
||||||
.event-list::-webkit-scrollbar,
|
|
||||||
.sidebar::-webkit-scrollbar {
|
|
||||||
width: 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.event-list::-webkit-scrollbar-track,
|
|
||||||
.sidebar::-webkit-scrollbar-track {
|
|
||||||
background: #f8fafc;
|
|
||||||
border-radius: 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.event-list::-webkit-scrollbar-thumb,
|
|
||||||
.sidebar::-webkit-scrollbar-thumb {
|
|
||||||
background: #cbd5e1;
|
|
||||||
border-radius: 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.event-list::-webkit-scrollbar-thumb:hover,
|
|
||||||
.sidebar::-webkit-scrollbar-thumb:hover {
|
|
||||||
background: #C60B24;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 반응형 디자인 - 태블릿 */
|
|
||||||
@media (max-width: 1024px) {
|
|
||||||
.container {
|
|
||||||
padding: 1rem;
|
|
||||||
gap: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.content-wrapper {
|
|
||||||
gap: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar {
|
|
||||||
width: 220px;
|
|
||||||
min-width: 200px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.event-img {
|
|
||||||
width: 220px;
|
|
||||||
min-width: 220px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.event-img img {
|
|
||||||
height: 140px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.header {
|
|
||||||
padding: 1.25rem 1.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.page-title {
|
|
||||||
font-size: clamp(1.375rem, 2.8vw, 1.75rem); /* 22px ~ 28px */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 반응형 디자인 - 모바일 */
|
|
||||||
@media (max-width: 768px) {
|
|
||||||
.container {
|
|
||||||
flex-direction: column;
|
|
||||||
padding: 1rem;
|
|
||||||
gap: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.content-wrapper {
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar {
|
|
||||||
width: 100%;
|
|
||||||
position: static;
|
|
||||||
max-height: none;
|
|
||||||
order: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.category-list {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
|
|
||||||
gap: 0.5rem;
|
|
||||||
padding: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.category-link {
|
|
||||||
text-align: center;
|
|
||||||
padding: 0.75rem 0.5rem;
|
|
||||||
font-size: 0.875rem; /* 14px */
|
|
||||||
}
|
|
||||||
|
|
||||||
.main-content {
|
|
||||||
order: 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
.event-list {
|
|
||||||
overflow-y: visible;
|
|
||||||
height: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.event-card {
|
|
||||||
flex-direction: column;
|
|
||||||
min-height: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.event-img {
|
|
||||||
width: 100%;
|
|
||||||
min-width: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.event-img img {
|
|
||||||
height: 200px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.event-info {
|
|
||||||
padding: 1.25rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.header {
|
|
||||||
padding: 1rem 1.5rem;
|
|
||||||
border-radius: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.page-title {
|
|
||||||
font-size: clamp(1.25rem, 2.5vw, 1.5rem); /* 20px ~ 24px */
|
|
||||||
}
|
|
||||||
|
|
||||||
.event-title {
|
|
||||||
font-size: 1.125rem; /* 18px */
|
|
||||||
}
|
|
||||||
|
|
||||||
.event-price {
|
|
||||||
font-size: 1rem; /* 16px */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 작은 모바일 */
|
|
||||||
@media (max-width: 480px) {
|
|
||||||
.container {
|
|
||||||
padding: 0.75rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.header {
|
|
||||||
padding: 0.875rem 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.page-title {
|
|
||||||
font-size: clamp(1.125rem, 2.2vw, 1.375rem); /* 18px ~ 22px */
|
|
||||||
}
|
|
||||||
|
|
||||||
.event-info {
|
|
||||||
padding: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.event-title {
|
|
||||||
font-size: 1rem; /* 16px */
|
|
||||||
}
|
|
||||||
|
|
||||||
.event-desc {
|
|
||||||
font-size: 0.875rem; /* 14px */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</th:block>
|
</th:block>
|
||||||
|
|
||||||
<th:block layout:fragment="layout_top_script">
|
<th:block layout:fragment="layout_top_script">
|
||||||
@@ -411,7 +22,6 @@ const CDN_URL = [[${@environment.getProperty('url.cdn')}]];
|
|||||||
<div class="content-wrapper">
|
<div class="content-wrapper">
|
||||||
<!-- 좌측 사이드바 -->
|
<!-- 좌측 사이드바 -->
|
||||||
<aside class="sidebar">
|
<aside class="sidebar">
|
||||||
<div class="sidebar-header">이달의 이벤트</div>
|
|
||||||
<ul class="category-list" id="category-list">
|
<ul class="category-list" id="category-list">
|
||||||
<!-- 카테고리 JS로 렌더링 -->
|
<!-- 카테고리 JS로 렌더링 -->
|
||||||
</ul>
|
</ul>
|
||||||
@@ -427,168 +37,20 @@ const CDN_URL = [[${@environment.getProperty('url.cdn')}]];
|
|||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- 지난 이벤트 레이어 팝업 -->
|
||||||
|
<div class="popup-overlay" id="expired-popup">
|
||||||
|
<div class="popup-content">
|
||||||
|
<div class="popup-icon">⏰</div>
|
||||||
|
<div class="popup-title">지난 이벤트</div>
|
||||||
|
<div class="popup-message">이 이벤트는 종료되었습니다.<br>다른 진행 중인 이벤트를 확인해 주세요.</div>
|
||||||
|
<button class="popup-close-btn" onclick="eventManager.hideExpiredPopup()">확인</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</th:block>
|
</th:block>
|
||||||
|
|
||||||
<th:block layout:fragment="layoutContentScript">
|
<th:block layout:fragment="layoutContentScript">
|
||||||
<script>
|
<script th:src="@{/js/web/webevent/webEventSelectList.js}"></script>
|
||||||
class EventManager {
|
|
||||||
constructor() {
|
|
||||||
this.events = [];
|
|
||||||
this.categories = [];
|
|
||||||
this.init();
|
|
||||||
}
|
|
||||||
|
|
||||||
async init() {
|
|
||||||
await this.loadCategories();
|
|
||||||
}
|
|
||||||
|
|
||||||
async apiRequest(url, data) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
$.ajax({
|
|
||||||
url: encodeURI(url),
|
|
||||||
data: data,
|
|
||||||
dataType: 'json',
|
|
||||||
processData: false,
|
|
||||||
contentType: false,
|
|
||||||
type: 'POST',
|
|
||||||
success: resolve,
|
|
||||||
error: reject,
|
|
||||||
beforeSend: () => $(".loading-image-layer").show(),
|
|
||||||
complete: () => $(".loading-image-layer").hide()
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async loadCategories() {
|
|
||||||
try {
|
|
||||||
const formData = new FormData();
|
|
||||||
formData.append('bannerType', 'A');
|
|
||||||
const data = await this.apiRequest('/webevent/selectListWebEvent.do', formData);
|
|
||||||
|
|
||||||
if (data.msgCode === '0') {
|
|
||||||
this.categories = data.rows;
|
|
||||||
this.renderCategories();
|
|
||||||
if (this.categories.length > 0) {
|
|
||||||
this.loadEvents(this.categories[0].CATEGORY_NO);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
modalEvent.danger("조회 오류", data.msgDesc);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
modalEvent.danger("조회 오류", "조회 중 오류가 발생하였습니다.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async loadEvents(categoryNo) {
|
|
||||||
try {
|
|
||||||
const formData = new FormData();
|
|
||||||
formData.append('category_no', categoryNo);
|
|
||||||
const data = await this.apiRequest('/webevent/selectListEvent.do', formData);
|
|
||||||
|
|
||||||
if (data.msgCode === '0') {
|
|
||||||
this.events = data.rows.map(row => ({
|
|
||||||
img: CDN_URL + row.THUMBNAIL_PATH,
|
|
||||||
title: row.TITLE,
|
|
||||||
desc: row.CONTENT,
|
|
||||||
meta: row.THUMBNAIL_BOTTOM_TXT,
|
|
||||||
price: {
|
|
||||||
before: Number(row.PRICE) || 0,
|
|
||||||
after: Number(row.DISCOUNT_PRICE) || 0
|
|
||||||
},
|
|
||||||
categoryDiv: row.CATEGORY_DIV_CD,
|
|
||||||
categoryNo: row.CATEGORY_NO,
|
|
||||||
postNo: row.POST_NO
|
|
||||||
}));
|
|
||||||
this.renderEvents();
|
|
||||||
} else {
|
|
||||||
modalEvent.danger("조회 오류", data.msgDesc);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
modalEvent.danger("조회 오류", "조회 중 오류가 발생하였습니다.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
renderCategories() {
|
|
||||||
const html = this.categories.map((cat, idx) => `
|
|
||||||
<li class="category-item">
|
|
||||||
<a href="#" class="category-link ${idx === 0 ? 'active' : ''}"
|
|
||||||
data-category="${cat.CATEGORY_NO}">${cat.CATEGORY_NM}</a>
|
|
||||||
</li>
|
|
||||||
`).join('');
|
|
||||||
|
|
||||||
document.getElementById('category-list').innerHTML = html;
|
|
||||||
|
|
||||||
document.querySelectorAll('.category-link').forEach(link => {
|
|
||||||
link.addEventListener('click', (e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
document.querySelectorAll('.category-link').forEach(item =>
|
|
||||||
item.classList.remove('active'));
|
|
||||||
link.classList.add('active');
|
|
||||||
this.loadEvents(link.dataset.category);
|
|
||||||
document.querySelector('.event-list').scrollTop = 0;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
renderEvents() {
|
|
||||||
const html = this.events.map(event => `
|
|
||||||
<div class="event-card" data-category-div="${event.categoryDiv}"
|
|
||||||
data-category-no="${event.categoryNo}" data-post-no="${event.postNo}">
|
|
||||||
<div class="event-img">
|
|
||||||
<img src="${event.img}" alt="${event.title}">
|
|
||||||
</div>
|
|
||||||
<div class="event-info">
|
|
||||||
<div class="event-title">${event.title}</div>
|
|
||||||
<div class="event-desc">${event.desc}</div>
|
|
||||||
${event.meta ? `<div class="event-meta">${event.meta}</div>` : ''}
|
|
||||||
<div class="event-price">
|
|
||||||
<span style="text-decoration:line-through; color:#9ca3af; font-size:0.95em; margin-right:8px;">
|
|
||||||
${event.price.before.toLocaleString()}원
|
|
||||||
</span>
|
|
||||||
${event.price.after.toLocaleString()}원 부터
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
`).join('');
|
|
||||||
|
|
||||||
document.getElementById('event-grid').innerHTML = html;
|
|
||||||
|
|
||||||
// 카드 클릭 이벤트 추가
|
|
||||||
document.querySelectorAll('.event-card').forEach(card => {
|
|
||||||
card.addEventListener('click', () => {
|
|
||||||
const categoryDiv = card.dataset.categoryDiv;
|
|
||||||
const categoryNo = card.dataset.categoryNo;
|
|
||||||
const postNo = card.dataset.postNo;
|
|
||||||
this.goToDetail(categoryDiv, categoryNo, postNo);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
goToDetail(categoryDiv, categoryNo, postNo) {
|
|
||||||
const form = document.createElement('form');
|
|
||||||
form.method = 'post';
|
|
||||||
form.action = '/webevent/selectEventDetailIntro.do';
|
|
||||||
|
|
||||||
const fields = [
|
|
||||||
{ name: 'CATEGORY_DIV_CD', value: categoryDiv },
|
|
||||||
{ name: 'CATEGORY_NO', value: categoryNo },
|
|
||||||
{ name: 'POST_NO', value: postNo }
|
|
||||||
];
|
|
||||||
|
|
||||||
fields.forEach(field => {
|
|
||||||
const input = document.createElement('input');
|
|
||||||
input.type = 'hidden';
|
|
||||||
input.name = field.name;
|
|
||||||
input.value = field.value;
|
|
||||||
form.appendChild(input);
|
|
||||||
});
|
|
||||||
|
|
||||||
document.body.appendChild(form);
|
|
||||||
form.submit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const eventManager = new EventManager();
|
|
||||||
</script>
|
|
||||||
</th:block>
|
</th:block>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
|
||||||
|
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{/web/layout/layout}">
|
||||||
|
<th:block layout:fragment="layoutCss">
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/quill@2.0.3/dist/quill.snow.css" rel="stylesheet" />
|
||||||
|
<link rel="stylesheet" th:href="@{/css/web/webreview/procedureReviewSelect.css}" />
|
||||||
|
</th:block>
|
||||||
|
<th:block layout:fragment="layout_top_script">
|
||||||
|
<script th:inline="javascript">
|
||||||
|
const muProcedureReviewId = [[${ muProcedureReviewId }]];
|
||||||
|
const CDN_URL = [[${@environment.getProperty('url.cdn') }]];
|
||||||
|
</script>
|
||||||
|
</th:block>
|
||||||
|
<th:block layout:fragment="layoutContent">
|
||||||
|
<div class="container">
|
||||||
|
<div class="breadcrumb">
|
||||||
|
<a href="/webreview/selectListProcedureReviewIntro.do">고객후기</a>
|
||||||
|
<span>></span>
|
||||||
|
<span id="breadcrumb-title">상세보기</span>
|
||||||
|
</div>
|
||||||
|
<article class="review-article">
|
||||||
|
<div class="review-header">
|
||||||
|
<h1 class="review-title" id="review-title"></h1>
|
||||||
|
<div class="review-meta">
|
||||||
|
<span class="review-date" id="review-date"></span>
|
||||||
|
<span class="review-views">조회 <span id="review-views">0</span></span>
|
||||||
|
</div>
|
||||||
|
<div class="review-tags" id="review-tags"></div>
|
||||||
|
</div>
|
||||||
|
<div class="review-content" id="review-content">
|
||||||
|
<div class="loading">게시글을 불러오는 중...</div>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
<div class="btn-area">
|
||||||
|
<a href="/webreview/selectListProcedureReviewIntro.do" class="btn-list">목록으로</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</th:block>
|
||||||
|
<th:block layout:fragment="layoutContentScript">
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/quill@2.0.3/dist/quill.js"></script>
|
||||||
|
<script th:src="@{/js/web/webreview/procedureReviewSelect.js}"></script>
|
||||||
|
</th:block>
|
||||||
|
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
|
||||||
|
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{/web/layout/layout}">
|
||||||
|
<th:block layout:fragment="layoutCss">
|
||||||
|
<link rel="stylesheet" th:href="@{/css/web/webreview/procedureReviewSelectList.css}" />
|
||||||
|
</th:block>
|
||||||
|
<th:block layout:fragment="layout_top_script">
|
||||||
|
<script th:inline="javascript">
|
||||||
|
const CDN_URL = [[${@environment.getProperty('url.cdn') }]];
|
||||||
|
</script>
|
||||||
|
</th:block>
|
||||||
|
<th:block layout:fragment="layoutContent">
|
||||||
|
<div class="container">
|
||||||
|
<div class="header">
|
||||||
|
<h1 class="page-title">고객후기</h1>
|
||||||
|
<p class="page-subtitle">실제 고객님들의 생생한 후기를 확인하세요</p>
|
||||||
|
</div>
|
||||||
|
<div class="search-area">
|
||||||
|
<div class="search-box">
|
||||||
|
<input type="text" id="searchTitle" placeholder="제목으로 검색" />
|
||||||
|
<button id="btnSearch" class="search-btn">검색</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="review-grid" id="review-grid">
|
||||||
|
<div class="loading">고객후기를 불러오는 중...</div>
|
||||||
|
</div>
|
||||||
|
<div class="pagination-area" id="pagination-area"></div>
|
||||||
|
</div>
|
||||||
|
</th:block>
|
||||||
|
<th:block layout:fragment="layoutContentScript">
|
||||||
|
<script th:src="@{/js/web/webreview/procedureReviewSelectList.js}"></script>
|
||||||
|
</th:block>
|
||||||
|
|
||||||
|
</html>
|
||||||