Compare commits
34 Commits
6ff468b5e0
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 441f3ce30b | |||
| 8e26533e2f | |||
| cd7f38378d | |||
| 6ee8124cda | |||
| 06c2a8c90e | |||
| 9b6d4dc4c8 | |||
| 4d74b497d4 | |||
| f3d3780ef9 | |||
| cd0fb5584e | |||
| ce39cc5c99 | |||
| f7e00b745f | |||
| 259af715b8 | |||
| f0a61d80d9 | |||
| b4248b7bf3 | |||
| fbe06f35dd | |||
| 559e99b050 | |||
| cacfdfb943 | |||
| bec0b3338b | |||
|
|
957652682f | ||
|
|
75618dad0d | ||
|
|
4f2b9fd2a2 | ||
|
|
8b637c0a84 | ||
|
|
ac1ca3020a | ||
|
|
81ff7701b6 | ||
|
|
38fa238bc5 | ||
|
|
3e0cdab291 | ||
|
|
f935efaa93 | ||
|
|
9efdac26cb | ||
|
|
6bb3ae8f7c | ||
|
|
b73b3fd3f7 | ||
|
|
37664d94ef | ||
|
|
677bd4d818 | ||
|
|
76bbfca086 | ||
|
|
c5d4bee27c |
1
.wiki
Submodule
11
Walkthrough.md
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# MadeU Diet Home - 프로젝트 Walkthrough
|
||||||
|
|
||||||
|
최근 개발 환경 및 시스템에 적용된 주요 변경 사항과 기능 구현 내역을 요약한 문서입니다.
|
||||||
|
|
||||||
|
## 1. 프로젝트 초기 구성 및 구동 안정화
|
||||||
|
- **저장소 구축**: Git 저장소 초기 클론을 통한 환경 구성 및 초기화를 완료했습니다.
|
||||||
|
- **프록시 및 로컬 구동 트러블슈팅**: Jenkins를 넘나드는 리버스 프록시(Reverse Proxy) 설정 오류 및 로컬 개발 환경에서 프로젝트 구동 시 발생했던 구성 요소 이슈를 파악하고 정상화했습니다.
|
||||||
|
|
||||||
|
## 2. 검색 엔진 최적화(SEO) 및 메타 데이터 구축
|
||||||
|
- **메타 태그 수정**: 웹 페이지 헤더 영역의 `meta` 태그 관련 속성을 최적화하여 페이지 렌더링 및 정보 제공의 정확도를 향상시켰습니다.
|
||||||
|
- **Open Graph (OG) 태그 적용**: 카카오톡, 페이스북, 인스타그램 등 외부 소셜 미디어를 통해 웹사이트 링크가 공유될 때, 알맞은 이미지와 설명 및 타이틀이 카드 형태로 매끄럽게 표시되도록 `og:title`, `og:image`, `og:description` 등의 기능을 추가했습니다.
|
||||||
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") ) {
|
/*
|
||||||
return menuService.getMenuHierarchy("MAIN");
|
* if (requestURI.endsWith("Intro.do") || requestURI.startsWith("/index") ) {
|
||||||
}
|
* return menuService.getMenuHierarchy("MAIN"); }
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
return new ArrayList<>();
|
return menuService.getMenuHierarchy("MAIN");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,10 +18,9 @@ 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 {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private WebEventService webEventService;
|
private WebEventService webEventService;
|
||||||
@@ -36,8 +35,8 @@ public class WebEventController extends ManagerDraftAction{
|
|||||||
* @param response
|
* @param response
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@RequestMapping(value="/webevent/selectListWebEventIntro.do")
|
@RequestMapping(value = "/webevent/selectListWebEventIntro.do")
|
||||||
public String selectListWebEventIntro(HttpSession session,HttpServletRequest request) {
|
public String selectListWebEventIntro(HttpSession session, HttpServletRequest request) {
|
||||||
|
|
||||||
log.debug("WebEventController selectListWebEventIntro START");
|
log.debug("WebEventController selectListWebEventIntro START");
|
||||||
|
|
||||||
@@ -52,33 +51,34 @@ public class WebEventController extends ManagerDraftAction{
|
|||||||
* @param response
|
* @param response
|
||||||
* @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");
|
||||||
|
|
||||||
HashMap<String, Object> paramMap = HttpUtil.getParameterMap(request);
|
HashMap<String, Object> paramMap = HttpUtil.getParameterMap(request);
|
||||||
HashMap<String, Object> map = new HashMap<String, Object>();
|
HashMap<String, Object> map = new HashMap<String, Object>();
|
||||||
StringBuffer errorMsg = new StringBuffer();
|
StringBuffer errorMsg = new StringBuffer();
|
||||||
|
|
||||||
try{
|
try {
|
||||||
map = webEventService.selectListWebEvent(paramMap);
|
map = webEventService.selectListWebEvent(paramMap);
|
||||||
log.debug(map + "");
|
log.debug(map + "");
|
||||||
}catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
errorMsg.append(e);
|
errorMsg.append(e);
|
||||||
return null;
|
return null;
|
||||||
}finally {
|
} finally {
|
||||||
if(Constants.OK == map.get("msgCode")) {
|
if (Constants.OK == map.get("msgCode")) {
|
||||||
|
|
||||||
}else{
|
} else {
|
||||||
if(null == map.get("msgCode") || ("").equals(map.get("msgCode"))) {
|
if (null == map.get("msgCode") || ("").equals(map.get("msgCode"))) {
|
||||||
map.put("msgCode", Constants.FAIL);
|
map.put("msgCode", Constants.FAIL);
|
||||||
}
|
}
|
||||||
|
|
||||||
map.put("success", false);
|
map.put("success", false);
|
||||||
if(null == map.get("msgDesc") || ("").equals(map.get("msgDesc"))) {
|
if (null == map.get("msgDesc") || ("").equals(map.get("msgDesc"))) {
|
||||||
map.put("msgDesc","정상적으로 수행되지 않았습니다. 관리자에게 문의하시기 바랍니다. (E0029)");
|
map.put("msgDesc", "정상적으로 수행되지 않았습니다. 관리자에게 문의하시기 바랍니다. (E0029)");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,27 +94,26 @@ public class WebEventController extends ManagerDraftAction{
|
|||||||
insertMap.put("requestValue", String.valueOf(paramMap));
|
insertMap.put("requestValue", String.valueOf(paramMap));
|
||||||
insertMap.put("responseValue", String.valueOf(map));
|
insertMap.put("responseValue", String.valueOf(map));
|
||||||
;
|
;
|
||||||
if(("true").equals(String.valueOf(map.get("success")))){
|
if (("true").equals(String.valueOf(map.get("success")))) {
|
||||||
insertMap.put("resultCode", "SUCCESS");
|
insertMap.put("resultCode", "SUCCESS");
|
||||||
}else{
|
} else {
|
||||||
insertMap.put("resultCode", "ERROR");
|
insertMap.put("resultCode", "ERROR");
|
||||||
}
|
}
|
||||||
|
|
||||||
insertMap.put("resultMsg", String.valueOf(errorMsg));
|
insertMap.put("resultMsg", String.valueOf(errorMsg));
|
||||||
insertMap.put("muMemberId", paramMap.get("muMemberId"));
|
insertMap.put("muMemberId", paramMap.get("muMemberId"));
|
||||||
|
|
||||||
// logHistoryService.insertLogHistory(insertMap, visitLogParamMap);
|
// logHistoryService.insertLogHistory(insertMap, visitLogParamMap);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log.debug("WebEventController selectListWebEvent END");
|
log.debug("WebEventController selectListWebEvent END");
|
||||||
|
|
||||||
|
|
||||||
return HttpUtil.makeHashToJsonModelAndView(map);
|
return HttpUtil.makeHashToJsonModelAndView(map);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 이벤트 별 항목 목록 조회
|
* 이벤트 별 항목 목록 조회
|
||||||
*
|
*
|
||||||
@@ -122,33 +121,33 @@ public class WebEventController extends ManagerDraftAction{
|
|||||||
* @param response
|
* @param response
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@RequestMapping(value="/webevent/selectListEvent.do")
|
@RequestMapping(value = "/webevent/selectListEvent.do")
|
||||||
public ModelAndView selectListEvent(HttpSession session,HttpServletRequest request, HttpServletResponse response) {
|
public ModelAndView selectListEvent(HttpSession session, HttpServletRequest request, HttpServletResponse response) {
|
||||||
|
|
||||||
log.debug("WebEventController selectListEvent START");
|
log.debug("WebEventController selectListEvent START");
|
||||||
|
|
||||||
HashMap<String, Object> paramMap = HttpUtil.getParameterMap(request);
|
HashMap<String, Object> paramMap = HttpUtil.getParameterMap(request);
|
||||||
HashMap<String, Object> map = new HashMap<String, Object>();
|
HashMap<String, Object> map = new HashMap<String, Object>();
|
||||||
StringBuffer errorMsg = new StringBuffer();
|
StringBuffer errorMsg = new StringBuffer();
|
||||||
|
|
||||||
try{
|
try {
|
||||||
map = webEventService.selectListEvent(paramMap);
|
map = webEventService.selectListEvent(paramMap);
|
||||||
log.debug(map + "");
|
log.debug(map + "");
|
||||||
}catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
errorMsg.append(e);
|
errorMsg.append(e);
|
||||||
return null;
|
return null;
|
||||||
}finally {
|
} finally {
|
||||||
if(Constants.OK == map.get("msgCode")) {
|
if (Constants.OK == map.get("msgCode")) {
|
||||||
|
|
||||||
}else{
|
} else {
|
||||||
if(null == map.get("msgCode") || ("").equals(map.get("msgCode"))) {
|
if (null == map.get("msgCode") || ("").equals(map.get("msgCode"))) {
|
||||||
map.put("msgCode", Constants.FAIL);
|
map.put("msgCode", Constants.FAIL);
|
||||||
}
|
}
|
||||||
|
|
||||||
map.put("success", false);
|
map.put("success", false);
|
||||||
if(null == map.get("msgDesc") || ("").equals(map.get("msgDesc"))) {
|
if (null == map.get("msgDesc") || ("").equals(map.get("msgDesc"))) {
|
||||||
map.put("msgDesc","정상적으로 수행되지 않았습니다. 관리자에게 문의하시기 바랍니다. (E0029)");
|
map.put("msgDesc", "정상적으로 수행되지 않았습니다. 관리자에게 문의하시기 바랍니다. (E0029)");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -164,23 +163,22 @@ public class WebEventController extends ManagerDraftAction{
|
|||||||
insertMap.put("requestValue", String.valueOf(paramMap));
|
insertMap.put("requestValue", String.valueOf(paramMap));
|
||||||
insertMap.put("responseValue", String.valueOf(map));
|
insertMap.put("responseValue", String.valueOf(map));
|
||||||
;
|
;
|
||||||
if(("true").equals(String.valueOf(map.get("success")))){
|
if (("true").equals(String.valueOf(map.get("success")))) {
|
||||||
insertMap.put("resultCode", "SUCCESS");
|
insertMap.put("resultCode", "SUCCESS");
|
||||||
}else{
|
} else {
|
||||||
insertMap.put("resultCode", "ERROR");
|
insertMap.put("resultCode", "ERROR");
|
||||||
}
|
}
|
||||||
|
|
||||||
insertMap.put("resultMsg", String.valueOf(errorMsg));
|
insertMap.put("resultMsg", String.valueOf(errorMsg));
|
||||||
|
|
||||||
// logHistoryService.insertLogHistory(insertMap, visitLogParamMap);
|
// logHistoryService.insertLogHistory(insertMap, visitLogParamMap);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log.debug("WebEventController selectListEvent END");
|
log.debug("WebEventController selectListEvent END");
|
||||||
|
|
||||||
|
|
||||||
return HttpUtil.makeHashToJsonModelAndView(map);
|
return HttpUtil.makeHashToJsonModelAndView(map);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -191,19 +189,19 @@ public class WebEventController extends ManagerDraftAction{
|
|||||||
* @param response
|
* @param response
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@RequestMapping(value="/webevent/selectEventDetailIntro.do")
|
@RequestMapping(value = "/webevent/selectEventDetailIntro.do")
|
||||||
public String selectEventDetailIntro(HttpSession session, HttpServletRequest request, Model model) {
|
public String selectEventDetailIntro(HttpSession session, HttpServletRequest request, Model model) {
|
||||||
|
|
||||||
log.debug("WebEventController selectEventDetailIntro START");
|
log.debug("WebEventController selectEventDetailIntro START");
|
||||||
HashMap<String, Object> paramMap = HttpUtil.getParameterMap(request);
|
HashMap<String, Object> paramMap = HttpUtil.getParameterMap(request);
|
||||||
model.addAttribute("CATEGORY_DIV_CD", paramMap.get("CATEGORY_DIV_CD"));
|
model.addAttribute("CATEGORY_DIV_CD", paramMap.get("CATEGORY_DIV_CD"));
|
||||||
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"));
|
||||||
log.debug("WebEventController selectEventDetailIntro END");
|
log.debug("WebEventController selectEventDetailIntro END");
|
||||||
|
|
||||||
return "/web/webevent/webEventSelect";
|
return "/web/webevent/webEventSelect";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 이벤트 안내 목록 상세 조회
|
* 이벤트 안내 목록 상세 조회
|
||||||
*
|
*
|
||||||
@@ -211,33 +209,34 @@ public class WebEventController extends ManagerDraftAction{
|
|||||||
* @param response
|
* @param response
|
||||||
* @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");
|
||||||
|
|
||||||
HashMap<String, Object> paramMap = HttpUtil.getParameterMap(request);
|
HashMap<String, Object> paramMap = HttpUtil.getParameterMap(request);
|
||||||
HashMap<String, Object> map = new HashMap<String, Object>();
|
HashMap<String, Object> map = new HashMap<String, Object>();
|
||||||
StringBuffer errorMsg = new StringBuffer();
|
StringBuffer errorMsg = new StringBuffer();
|
||||||
|
|
||||||
try{
|
try {
|
||||||
map = webEventService.selectEventDetail(paramMap);
|
map = webEventService.selectEventDetail(paramMap);
|
||||||
log.debug(map + "");
|
log.debug(map + "");
|
||||||
}catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
errorMsg.append(e);
|
errorMsg.append(e);
|
||||||
return null;
|
return null;
|
||||||
}finally {
|
} finally {
|
||||||
if(Constants.OK == map.get("msgCode")) {
|
if (Constants.OK == map.get("msgCode")) {
|
||||||
|
|
||||||
}else{
|
} else {
|
||||||
if(null == map.get("msgCode") || ("").equals(map.get("msgCode"))) {
|
if (null == map.get("msgCode") || ("").equals(map.get("msgCode"))) {
|
||||||
map.put("msgCode", Constants.FAIL);
|
map.put("msgCode", Constants.FAIL);
|
||||||
}
|
}
|
||||||
|
|
||||||
map.put("success", false);
|
map.put("success", false);
|
||||||
if(null == map.get("msgDesc") || ("").equals(map.get("msgDesc"))) {
|
if (null == map.get("msgDesc") || ("").equals(map.get("msgDesc"))) {
|
||||||
map.put("msgDesc","정상적으로 수행되지 않았습니다. 관리자에게 문의하시기 바랍니다. (E0029)");
|
map.put("msgDesc", "정상적으로 수행되지 않았습니다. 관리자에게 문의하시기 바랍니다. (E0029)");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -253,27 +252,26 @@ public class WebEventController extends ManagerDraftAction{
|
|||||||
insertMap.put("requestValue", String.valueOf(paramMap));
|
insertMap.put("requestValue", String.valueOf(paramMap));
|
||||||
insertMap.put("responseValue", String.valueOf(map));
|
insertMap.put("responseValue", String.valueOf(map));
|
||||||
;
|
;
|
||||||
if(("true").equals(String.valueOf(map.get("success")))){
|
if (("true").equals(String.valueOf(map.get("success")))) {
|
||||||
insertMap.put("resultCode", "SUCCESS");
|
insertMap.put("resultCode", "SUCCESS");
|
||||||
}else{
|
} else {
|
||||||
insertMap.put("resultCode", "ERROR");
|
insertMap.put("resultCode", "ERROR");
|
||||||
}
|
}
|
||||||
|
|
||||||
insertMap.put("resultMsg", String.valueOf(errorMsg));
|
insertMap.put("resultMsg", String.valueOf(errorMsg));
|
||||||
|
|
||||||
// logHistoryService.insertLogHistory(insertMap, visitLogParamMap);
|
// logHistoryService.insertLogHistory(insertMap, visitLogParamMap);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log.debug("WebEventController selectEventDetail END");
|
log.debug("WebEventController selectEventDetail END");
|
||||||
|
|
||||||
|
|
||||||
return HttpUtil.makeHashToJsonModelAndView(map);
|
return HttpUtil.makeHashToJsonModelAndView(map);
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequestMapping(value="/webevent/selectMakeReservation.do")
|
@RequestMapping(value = "/webevent/selectMakeReservation.do")
|
||||||
public String selectMakeReservation(HttpSession session, HttpServletRequest request, Model model) {
|
public String selectMakeReservation(HttpSession session, HttpServletRequest request, Model model) {
|
||||||
|
|
||||||
log.debug("WebServiceController selectMakeReservation START");
|
log.debug("WebServiceController selectMakeReservation START");
|
||||||
@@ -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";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 시술 목록 상세 조회
|
|
||||||
*
|
|
||||||
* @param request
|
|
||||||
* @param response
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
@RequestMapping(value="/webevent/selectReservation.do")
|
|
||||||
public ModelAndView selectReservation(HttpSession session, HttpServletRequest request, HttpServletResponse response) {
|
|
||||||
|
|
||||||
log.debug("WebServiceController selectReservation START");
|
return "/web/service/makeReservation";
|
||||||
|
|
||||||
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,32 +5,31 @@ 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
|
||||||
@Controller
|
@Controller
|
||||||
public class WebHomeController extends ManagerDraftAction{
|
public class WebHomeController extends ManagerDraftAction {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 홈 화면으로 이동.
|
* 홈 화면으로 이동.
|
||||||
*
|
*
|
||||||
* @param request
|
* @param request
|
||||||
* @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 "redirect:/webservice/selectServiceDetailIntro.do?categoryDivCd=01&categoryNo=1&postNo=1";
|
||||||
}
|
}
|
||||||
|
|
||||||
@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");
|
||||||
|
|
||||||
log.debug("WebHomeController homeIndex END");
|
log.debug("WebHomeController homeIndex END");
|
||||||
|
|||||||
@@ -0,0 +1,117 @@
|
|||||||
|
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";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 시술후기 리스트 조회 (AJAX)
|
||||||
|
*/
|
||||||
|
@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>();
|
||||||
|
StringBuffer errorMsg = new StringBuffer();
|
||||||
|
|
||||||
|
try {
|
||||||
|
map = webReviewService.selectListProcedureReview(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("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";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 시술후기 상세 조회 (AJAX)
|
||||||
|
*/
|
||||||
|
@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>();
|
||||||
|
StringBuffer errorMsg = new StringBuffer();
|
||||||
|
|
||||||
|
try {
|
||||||
|
map = webReviewService.selectProcedureReview(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("WebReviewController selectProcedureReview END");
|
||||||
|
return HttpUtil.makeHashToJsonModelAndView(map);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -25,13 +25,12 @@ 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 {
|
||||||
@Autowired
|
@Autowired
|
||||||
private WebServiceService webServiceService;
|
private WebServiceService webServiceService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 시술관리 목록으로 이동.
|
* 시술관리 목록으로 이동.
|
||||||
*
|
*
|
||||||
@@ -39,16 +38,16 @@ public class WebServiceController extends ManagerDraftAction{
|
|||||||
* @param response
|
* @param response
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@RequestMapping(value="/webservice/selectServiceIntro.do")
|
@RequestMapping(value = "/webservice/selectServiceIntro.do")
|
||||||
public String selectListServiceIntro(HttpSession session,HttpServletRequest request) {
|
public String selectListServiceIntro(HttpSession session, HttpServletRequest request) {
|
||||||
|
|
||||||
log.debug("WebServiceController selectListServiceIntro START");
|
log.debug("WebServiceController selectListServiceIntro START");
|
||||||
|
|
||||||
log.debug("WebServiceController selectListServiceIntro END");
|
log.debug("WebServiceController selectListServiceIntro END");
|
||||||
|
|
||||||
return "/web/service/serviceInfo";
|
return "/web/service/serviceInfo";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 시술관리 카테고리 목록 조회
|
* 시술관리 카테고리 목록 조회
|
||||||
*
|
*
|
||||||
@@ -56,33 +55,34 @@ public class WebServiceController extends ManagerDraftAction{
|
|||||||
* @param response
|
* @param response
|
||||||
* @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");
|
||||||
|
|
||||||
HashMap<String, Object> paramMap = HttpUtil.getParameterMap(request);
|
HashMap<String, Object> paramMap = HttpUtil.getParameterMap(request);
|
||||||
HashMap<String, Object> map = new HashMap<String, Object>();
|
HashMap<String, Object> map = new HashMap<String, Object>();
|
||||||
StringBuffer errorMsg = new StringBuffer();
|
StringBuffer errorMsg = new StringBuffer();
|
||||||
|
|
||||||
try{
|
try {
|
||||||
map = webServiceService.selectListWebCategory(paramMap);
|
map = webServiceService.selectListWebCategory(paramMap);
|
||||||
log.debug(map + "");
|
log.debug(map + "");
|
||||||
}catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
errorMsg.append(e);
|
errorMsg.append(e);
|
||||||
return null;
|
return null;
|
||||||
}finally {
|
} finally {
|
||||||
if(Constants.OK == map.get("msgCode")) {
|
if (Constants.OK == map.get("msgCode")) {
|
||||||
|
|
||||||
}else{
|
} else {
|
||||||
if(null == map.get("msgCode") || ("").equals(map.get("msgCode"))) {
|
if (null == map.get("msgCode") || ("").equals(map.get("msgCode"))) {
|
||||||
map.put("msgCode", Constants.FAIL);
|
map.put("msgCode", Constants.FAIL);
|
||||||
}
|
}
|
||||||
|
|
||||||
map.put("success", false);
|
map.put("success", false);
|
||||||
if(null == map.get("msgDesc") || ("").equals(map.get("msgDesc"))) {
|
if (null == map.get("msgDesc") || ("").equals(map.get("msgDesc"))) {
|
||||||
map.put("msgDesc","정상적으로 수행되지 않았습니다. 관리자에게 문의하시기 바랍니다. (E0029)");
|
map.put("msgDesc", "정상적으로 수행되지 않았습니다. 관리자에게 문의하시기 바랍니다. (E0029)");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,27 +98,26 @@ public class WebServiceController extends ManagerDraftAction{
|
|||||||
insertMap.put("requestValue", String.valueOf(paramMap));
|
insertMap.put("requestValue", String.valueOf(paramMap));
|
||||||
insertMap.put("responseValue", String.valueOf(map));
|
insertMap.put("responseValue", String.valueOf(map));
|
||||||
;
|
;
|
||||||
if(("true").equals(String.valueOf(map.get("success")))){
|
if (("true").equals(String.valueOf(map.get("success")))) {
|
||||||
insertMap.put("resultCode", "SUCCESS");
|
insertMap.put("resultCode", "SUCCESS");
|
||||||
}else{
|
} else {
|
||||||
insertMap.put("resultCode", "ERROR");
|
insertMap.put("resultCode", "ERROR");
|
||||||
}
|
}
|
||||||
|
|
||||||
insertMap.put("resultMsg", String.valueOf(errorMsg));
|
insertMap.put("resultMsg", String.valueOf(errorMsg));
|
||||||
insertMap.put("muMemberId", paramMap.get("muMemberId"));
|
insertMap.put("muMemberId", paramMap.get("muMemberId"));
|
||||||
|
|
||||||
// logHistoryService.insertLogHistory(insertMap, visitLogParamMap);
|
// logHistoryService.insertLogHistory(insertMap, visitLogParamMap);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log.debug("WebServiceController selectListCategory END");
|
log.debug("WebServiceController selectListCategory END");
|
||||||
|
|
||||||
|
|
||||||
return HttpUtil.makeHashToJsonModelAndView(map);
|
return HttpUtil.makeHashToJsonModelAndView(map);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 카테고리 별 시술 목록 조회
|
* 카테고리 별 시술 목록 조회
|
||||||
*
|
*
|
||||||
@@ -126,28 +125,28 @@ public class WebServiceController extends ManagerDraftAction{
|
|||||||
* @param response
|
* @param response
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@PostMapping(value="/webservice/selectListService.do")
|
@PostMapping(value = "/webservice/selectListService.do")
|
||||||
@ResponseBody
|
@ResponseBody
|
||||||
public ResponseEntity<Map<String, Object>> selectListService(@RequestParam("categoryNo") String categoryNo) {
|
public ResponseEntity<Map<String, Object>> selectListService(@RequestParam("categoryNo") String categoryNo) {
|
||||||
|
|
||||||
Map<String, Object> response = new HashMap<>();
|
Map<String, Object> response = new HashMap<>();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
HashMap<String, Object> paramMap = new HashMap<>();
|
HashMap<String, Object> paramMap = new HashMap<>();
|
||||||
paramMap.put("categoryNo", categoryNo);
|
paramMap.put("categoryNo", categoryNo);
|
||||||
|
|
||||||
Map<String, Object> result = webServiceService.selectListWebService(paramMap);
|
Map<String, Object> result = webServiceService.selectListWebService(paramMap);
|
||||||
return ResponseEntity.ok(result);
|
return ResponseEntity.ok(result);
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("서비스 조회 실패", e);
|
log.error("서비스 조회 실패", e);
|
||||||
response.put("msgCode", Constants.FAIL);
|
response.put("msgCode", Constants.FAIL);
|
||||||
response.put("msgDesc", e.getMessage());
|
response.put("msgDesc", e.getMessage());
|
||||||
response.put("rows", new ArrayList<>());
|
response.put("rows", new ArrayList<>());
|
||||||
return ResponseEntity.ok(response);
|
return ResponseEntity.ok(response);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 시술관리 상세로 이동.
|
* 시술관리 상세로 이동.
|
||||||
*
|
*
|
||||||
@@ -155,19 +154,19 @@ public class WebServiceController extends ManagerDraftAction{
|
|||||||
* @param response
|
* @param response
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@RequestMapping(value="/webservice/selectServiceDetailIntro.do")
|
@RequestMapping(value = "/webservice/selectServiceDetailIntro.do")
|
||||||
public String selectServiceDetailIntro(HttpSession session, HttpServletRequest request, Model model) {
|
public String selectServiceDetailIntro(HttpSession session, HttpServletRequest request, Model model) {
|
||||||
|
|
||||||
log.debug("WebServiceController selectServiceDetailIntro START");
|
log.debug("WebServiceController selectServiceDetailIntro START");
|
||||||
HashMap<String, Object> paramMap = HttpUtil.getParameterMap(request);
|
HashMap<String, Object> paramMap = HttpUtil.getParameterMap(request);
|
||||||
model.addAttribute("CATEGORY_DIV_CD", paramMap.get("categoryDivCd"));
|
model.addAttribute("CATEGORY_DIV_CD", paramMap.get("categoryDivCd"));
|
||||||
model.addAttribute("CATEGORY_NO", paramMap.get("categoryNo"));
|
model.addAttribute("CATEGORY_NO", paramMap.get("categoryNo"));
|
||||||
model.addAttribute("POST_NO", paramMap.get("postNo"));
|
model.addAttribute("POST_NO", paramMap.get("postNo"));
|
||||||
log.debug("WebServiceController selectServiceDetailIntro END");
|
log.debug("WebServiceController selectServiceDetailIntro END");
|
||||||
|
|
||||||
return "/web/service/webServiceDetail";
|
return "/web/service/webServiceDetail";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 시술 목록 상세 조회
|
* 시술 목록 상세 조회
|
||||||
*
|
*
|
||||||
@@ -175,32 +174,33 @@ public class WebServiceController extends ManagerDraftAction{
|
|||||||
* @param response
|
* @param response
|
||||||
* @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");
|
||||||
|
|
||||||
HashMap<String, Object> paramMap = HttpUtil.getParameterMap(request);
|
HashMap<String, Object> paramMap = HttpUtil.getParameterMap(request);
|
||||||
HashMap<String, Object> map = new HashMap<String, Object>();
|
HashMap<String, Object> map = new HashMap<String, Object>();
|
||||||
StringBuffer errorMsg = new StringBuffer();
|
StringBuffer errorMsg = new StringBuffer();
|
||||||
|
|
||||||
try{
|
try {
|
||||||
map = webServiceService.selectServiceDetail(paramMap);
|
map = webServiceService.selectServiceDetail(paramMap);
|
||||||
}catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
errorMsg.append(e);
|
errorMsg.append(e);
|
||||||
return null;
|
return null;
|
||||||
}finally {
|
} finally {
|
||||||
if(Constants.OK == map.get("msgCode")) {
|
if (Constants.OK == map.get("msgCode")) {
|
||||||
|
|
||||||
}else{
|
} else {
|
||||||
if(null == map.get("msgCode") || ("").equals(map.get("msgCode"))) {
|
if (null == map.get("msgCode") || ("").equals(map.get("msgCode"))) {
|
||||||
map.put("msgCode", Constants.FAIL);
|
map.put("msgCode", Constants.FAIL);
|
||||||
}
|
}
|
||||||
|
|
||||||
map.put("success", false);
|
map.put("success", false);
|
||||||
if(null == map.get("msgDesc") || ("").equals(map.get("msgDesc"))) {
|
if (null == map.get("msgDesc") || ("").equals(map.get("msgDesc"))) {
|
||||||
map.put("msgDesc","정상적으로 수행되지 않았습니다. 관리자에게 문의하시기 바랍니다. (E0029)");
|
map.put("msgDesc", "정상적으로 수행되지 않았습니다. 관리자에게 문의하시기 바랍니다. (E0029)");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,243 +216,23 @@ public class WebServiceController extends ManagerDraftAction{
|
|||||||
insertMap.put("requestValue", String.valueOf(paramMap));
|
insertMap.put("requestValue", String.valueOf(paramMap));
|
||||||
insertMap.put("responseValue", String.valueOf(map));
|
insertMap.put("responseValue", String.valueOf(map));
|
||||||
;
|
;
|
||||||
if(("true").equals(String.valueOf(map.get("success")))){
|
if (("true").equals(String.valueOf(map.get("success")))) {
|
||||||
insertMap.put("resultCode", "SUCCESS");
|
insertMap.put("resultCode", "SUCCESS");
|
||||||
}else{
|
} else {
|
||||||
insertMap.put("resultCode", "ERROR");
|
insertMap.put("resultCode", "ERROR");
|
||||||
}
|
}
|
||||||
|
|
||||||
insertMap.put("resultMsg", String.valueOf(errorMsg));
|
insertMap.put("resultMsg", String.valueOf(errorMsg));
|
||||||
|
|
||||||
// logHistoryService.insertLogHistory(insertMap, visitLogParamMap);
|
// logHistoryService.insertLogHistory(insertMap, visitLogParamMap);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log.debug("WebServiceController selectServiceDetail END");
|
log.debug("WebServiceController selectServiceDetail END");
|
||||||
|
|
||||||
|
|
||||||
return HttpUtil.makeHashToJsonModelAndView(map);
|
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,68 @@
|
|||||||
|
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 {
|
||||||
|
logger.debug("WebReviewSqlMapDAO selectTotalProcedureReviewCount START");
|
||||||
|
String sqlId = "WebReview.selectTotalProcedureReviewCount";
|
||||||
|
logger.debug("WebReviewSqlMapDAO selectTotalProcedureReviewCount END");
|
||||||
|
return getSqlSession().selectOne(sqlId, paramMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 시술후기 리스트 조회
|
||||||
|
*/
|
||||||
|
public List<Map<String, Object>> selectListProcedureReview(HashMap<String, Object> paramMap)
|
||||||
|
throws DataAccessException {
|
||||||
|
logger.debug("WebReviewSqlMapDAO selectListProcedureReview START");
|
||||||
|
String sqlId = "WebReview.selectListProcedureReview";
|
||||||
|
logger.debug("WebReviewSqlMapDAO selectListProcedureReview END");
|
||||||
|
return getSqlSession().selectList(sqlId, paramMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 시술후기 상세 조회
|
||||||
|
*/
|
||||||
|
public Map<String, Object> selectProcedureReview(HashMap<String, Object> paramMap)
|
||||||
|
throws DataAccessException {
|
||||||
|
logger.debug("WebReviewSqlMapDAO selectProcedureReview START");
|
||||||
|
String sqlId = "WebReview.selectProcedureReview";
|
||||||
|
logger.debug("WebReviewSqlMapDAO selectProcedureReview END");
|
||||||
|
return getSqlSession().selectOne(sqlId, paramMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 시술후기 조회수 증가
|
||||||
|
*/
|
||||||
|
public void updateViewCount(HashMap<String, Object> paramMap)
|
||||||
|
throws DataAccessException {
|
||||||
|
logger.debug("WebReviewSqlMapDAO updateViewCount START");
|
||||||
|
String sqlId = "WebReview.updateViewCount";
|
||||||
|
getSqlSession().update(sqlId, paramMap);
|
||||||
|
logger.debug("WebReviewSqlMapDAO updateViewCount END");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -13,7 +13,7 @@ import org.springframework.stereotype.Repository;
|
|||||||
import jakarta.annotation.PostConstruct;
|
import jakarta.annotation.PostConstruct;
|
||||||
|
|
||||||
@Repository
|
@Repository
|
||||||
public class WebServiceSqlMapDAO extends SqlSessionDaoSupport{
|
public class WebServiceSqlMapDAO extends SqlSessionDaoSupport {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private SqlSessionTemplate sqlSessionTemplate;
|
private SqlSessionTemplate sqlSessionTemplate;
|
||||||
@@ -22,124 +22,74 @@ public class WebServiceSqlMapDAO extends SqlSessionDaoSupport{
|
|||||||
void init() {
|
void init() {
|
||||||
setSqlSessionTemplate(sqlSessionTemplate);
|
setSqlSessionTemplate(sqlSessionTemplate);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 시술관리 정보 카테고리 리스트 조회 (List)
|
* 시술관리 정보 카테고리 리스트 조회 (List)
|
||||||
*
|
*
|
||||||
* @param Map
|
* @param Map
|
||||||
* @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";
|
||||||
|
|
||||||
logger.debug("WebServiceSqlMapDAO selectListWebCategory END");
|
logger.debug("WebServiceSqlMapDAO selectListWebCategory END");
|
||||||
|
|
||||||
return getSqlSession().selectList(sqlId, paramMap);
|
return getSqlSession().selectList(sqlId, paramMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 시술관리 정보 시술 리스트 조회 (List)
|
* 시술관리 정보 시술 리스트 조회 (List)
|
||||||
*
|
*
|
||||||
* @param Map
|
* @param Map
|
||||||
* @return
|
* @return
|
||||||
* @throws DataAccessException
|
* @throws DataAccessException
|
||||||
*/
|
*/
|
||||||
public List<Map<String, Object>> selectListWebService(HashMap<String, Object> paramMap) throws DataAccessException {
|
public List<Map<String, Object>> selectListWebService(HashMap<String, Object> paramMap) throws DataAccessException {
|
||||||
logger.debug("WebServiceSqlMapDAO selectListWebService START");
|
logger.debug("WebServiceSqlMapDAO selectListWebService START");
|
||||||
|
|
||||||
String sqlId = "WebService.selectListWebService";
|
String sqlId = "WebService.selectListWebService";
|
||||||
|
|
||||||
logger.debug("WebServiceSqlMapDAO selectListWebService END");
|
logger.debug("WebServiceSqlMapDAO selectListWebService END");
|
||||||
|
|
||||||
return getSqlSession().selectList(sqlId, paramMap);
|
return getSqlSession().selectList(sqlId, paramMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 시술관리 정보 시술 상세 조회
|
* 시술관리 정보 시술 상세 조회
|
||||||
*
|
*
|
||||||
* @param Map
|
* @param Map
|
||||||
* @return
|
* @return
|
||||||
* @throws DataAccessException
|
* @throws DataAccessException
|
||||||
*/
|
*/
|
||||||
public Map<String, Object> selectServiceDetail(HashMap<String, Object> paramMap) throws DataAccessException {
|
public Map<String, Object> selectServiceDetail(HashMap<String, Object> paramMap) throws DataAccessException {
|
||||||
logger.debug("WebServiceSqlMapDAO selectServiceDetail START");
|
logger.debug("WebServiceSqlMapDAO selectServiceDetail START");
|
||||||
|
|
||||||
String sqlId = "WebService.selectServiceDetail";
|
String sqlId = "WebService.selectServiceDetail";
|
||||||
|
|
||||||
logger.debug("WebServiceSqlMapDAO selectServiceDetail END");
|
logger.debug("WebServiceSqlMapDAO selectServiceDetail END");
|
||||||
|
|
||||||
return getSqlSession().selectOne(sqlId, paramMap);
|
return getSqlSession().selectOne(sqlId, paramMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 시술관리 정보 시술 목록 조회 (List)
|
* 시술관리 정보 시술 목록 조회 (List)
|
||||||
*
|
*
|
||||||
* @param Map
|
* @param Map
|
||||||
* @return
|
* @return
|
||||||
* @throws DataAccessException
|
* @throws DataAccessException
|
||||||
*/
|
*/
|
||||||
public List<Map<String, Object>> selectListService(HashMap<String, Object> paramMap) throws DataAccessException {
|
public List<Map<String, Object>> selectListService(HashMap<String, Object> paramMap) throws DataAccessException {
|
||||||
logger.debug("WebServiceSqlMapDAO selectListService START");
|
logger.debug("WebServiceSqlMapDAO selectListService START");
|
||||||
|
|
||||||
String sqlId = "WebService.selectListService";
|
String sqlId = "WebService.selectListService";
|
||||||
|
|
||||||
logger.debug("WebServiceSqlMapDAO selectListService END");
|
logger.debug("WebServiceSqlMapDAO selectListService END");
|
||||||
|
|
||||||
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-2WlrXQdl-esws-5aA5-al7z-d7HwxL9tX0YF"
|
||||||
|
: (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,81 @@
|
|||||||
|
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,9 @@ 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,295 +1,114 @@
|
|||||||
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;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Service("WebServiceService")
|
@Service("WebServiceService")
|
||||||
public class WebServiceServiceImpl implements WebServiceService{
|
public class WebServiceServiceImpl implements WebServiceService {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private WebServiceSqlMapDAO webServiceSqlMapDAO;
|
private WebServiceSqlMapDAO webServiceSqlMapDAO;
|
||||||
|
|
||||||
@Value("${url.old-crm-php}")
|
|
||||||
private String ocp;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 시술 정보 카테고리 리스트 조회 (List)
|
* 시술 정보 카테고리 리스트 조회 (List)
|
||||||
*
|
*
|
||||||
* @param paramMap
|
* @param paramMap
|
||||||
* @return
|
* @return
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public HashMap<String, Object> selectListWebCategory(HashMap<String, Object> paramMap) throws Exception {
|
public HashMap<String, Object> selectListWebCategory(HashMap<String, Object> paramMap) throws Exception {
|
||||||
log.debug("WebServiceServiceImpl selectListWebCategory START");
|
log.debug("WebServiceServiceImpl selectListWebCategory START");
|
||||||
|
|
||||||
HashMap<String, Object> map = new HashMap<String, Object>();
|
HashMap<String, Object> map = new HashMap<String, Object>();
|
||||||
|
|
||||||
try{
|
try {
|
||||||
List<Map<String, Object>> listMap = webServiceSqlMapDAO.selectListWebCategory(paramMap);
|
List<Map<String, Object>> listMap = webServiceSqlMapDAO.selectListWebCategory(paramMap);
|
||||||
map.put("rows",listMap);
|
map.put("rows", listMap);
|
||||||
|
|
||||||
map.put("msgCode", Constants.OK);
|
map.put("msgCode", Constants.OK);
|
||||||
map.put("success","true");
|
map.put("success", "true");
|
||||||
|
|
||||||
}catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
|
|
||||||
log.debug("WebServiceServiceImpl selectListWebCategory END");
|
log.debug("WebServiceServiceImpl selectListWebCategory END");
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 시술 정보 리스트 조회 (List)
|
* 시술 정보 리스트 조회 (List)
|
||||||
*
|
*
|
||||||
* @param paramMap
|
* @param paramMap
|
||||||
* @return
|
* @return
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public HashMap<String, Object> selectListWebService(HashMap<String, Object> paramMap) throws Exception {
|
public HashMap<String, Object> selectListWebService(HashMap<String, Object> paramMap) throws Exception {
|
||||||
log.debug("WebServiceServiceImpl selectListWebService START");
|
log.debug("WebServiceServiceImpl selectListWebService START");
|
||||||
|
|
||||||
HashMap<String, Object> map = new HashMap<String, Object>();
|
HashMap<String, Object> map = new HashMap<String, Object>();
|
||||||
|
|
||||||
try{
|
try {
|
||||||
List<Map<String, Object>> listMap = webServiceSqlMapDAO.selectListWebService(paramMap);
|
List<Map<String, Object>> listMap = webServiceSqlMapDAO.selectListWebService(paramMap);
|
||||||
|
|
||||||
map.put("rows",listMap);
|
map.put("rows", listMap);
|
||||||
|
|
||||||
map.put("msgCode", Constants.OK);
|
map.put("msgCode", Constants.OK);
|
||||||
map.put("success","true");
|
map.put("success", "true");
|
||||||
|
|
||||||
}catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
|
|
||||||
log.debug("WebServiceServiceImpl selectListWebService END");
|
log.debug("WebServiceServiceImpl selectListWebService END");
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 시술 정보 상세 조회
|
* 시술 정보 상세 조회
|
||||||
*
|
*
|
||||||
* @param paramMap
|
* @param paramMap
|
||||||
* @return
|
* @return
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public HashMap<String, Object> selectServiceDetail(HashMap<String, Object> paramMap) throws Exception {
|
public HashMap<String, Object> selectServiceDetail(HashMap<String, Object> paramMap) throws Exception {
|
||||||
log.debug("WebServiceServiceImpl selectServiceDetail START");
|
log.debug("WebServiceServiceImpl selectServiceDetail START");
|
||||||
|
|
||||||
HashMap<String, Object> map = new HashMap<String, Object>();
|
HashMap<String, Object> map = new HashMap<String, Object>();
|
||||||
|
|
||||||
try{
|
try {
|
||||||
//상세 내용
|
// 상세 내용
|
||||||
Map<String, Object> listMap = webServiceSqlMapDAO.selectServiceDetail(paramMap);
|
Map<String, Object> listMap = webServiceSqlMapDAO.selectServiceDetail(paramMap);
|
||||||
map.put("rows",listMap);
|
map.put("rows", listMap);
|
||||||
//시술 목록
|
// 시술 목록
|
||||||
List<Map<String, Object>> listServiceMap = webServiceSqlMapDAO.selectListService(paramMap);
|
List<Map<String, Object>> listServiceMap = webServiceSqlMapDAO.selectListService(paramMap);
|
||||||
map.put("price",listServiceMap);
|
map.put("price", listServiceMap);
|
||||||
|
|
||||||
map.put("msgCode", Constants.OK);
|
|
||||||
map.put("success","true");
|
|
||||||
|
|
||||||
}catch (Exception e) {
|
map.put("msgCode", Constants.OK);
|
||||||
|
map.put("success", "true");
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
|
|
||||||
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-2WlrXQdl-esws-5aA5-al7z-d7HwxL9tX0YF" : (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:
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ spring:
|
|||||||
password: apdlemdb12#$
|
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: 17841468400622116
|
client-id: 17841468400622116
|
||||||
accesstoken: IGAAMzYDUuoLJBZAE04bnBiaHFicnBybGJrTVVYQmVBa0p0WV9XNVRXLUpiV0taTFJFelBBQTZAoeXhxckpLelcwMVAyQ1VMdGhpUUhydWZAnYWpJSXFGeXozcGNMOFFmWGEtTXRxWHFDMUpJRkcycGoxT2o5MlppY09mRWhNVUVxOAZDZD
|
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='DIET' 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='DIET' 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='DIET' 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 = 'DIET'
|
||||||
|
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 = '02'
|
AND A.CATEGORY_DIV_CD = '02'
|
||||||
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,
|
||||||
|
|||||||
68
src/main/resources/mappers/WebReviewSqlMap.xml
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
<?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 = '01'
|
AND A.CATEGORY_DIV_CD = '01'
|
||||||
AND A.CATEGORY_NO = #{categoryNo}
|
AND A.CATEGORY_NO = #{categoryNo}
|
||||||
|
ORDER BY ORD_NO DESC
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<!-- 카테고리 상세 조회 -->
|
<!-- 카테고리 상세 조회 -->
|
||||||
@@ -68,71 +69,5 @@
|
|||||||
AND A.CATEGORY_NO = #{CATEGORY_NO}
|
AND A.CATEGORY_NO = #{CATEGORY_NO}
|
||||||
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>
|
||||||
@@ -132,6 +132,10 @@
|
|||||||
color: #333;
|
color: #333;
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
line-height:16px;
|
||||||
|
word-break: keep-all;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: clip;
|
||||||
}
|
}
|
||||||
.popup .nav.nav-tabs li.active a,
|
.popup .nav.nav-tabs li.active a,
|
||||||
.popup .nav.nav-tabs li[role="presentation"].active a {
|
.popup .nav.nav-tabs li[role="presentation"].active a {
|
||||||
|
|||||||
493
src/main/resources/static/css/web/makeReservation.css
Normal file
@@ -0,0 +1,493 @@
|
|||||||
|
* {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: 'Noto Sans KR', sans-serif;
|
||||||
|
margin: 0;
|
||||||
|
background: #fafafa;
|
||||||
|
color: #222;
|
||||||
|
height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Main container */
|
||||||
|
.reservation-container {
|
||||||
|
display: flex;
|
||||||
|
max-width: 1280px !important;
|
||||||
|
margin: 0 auto;
|
||||||
|
gap: 20px;
|
||||||
|
height: 100%;
|
||||||
|
flex: 1;
|
||||||
|
padding: 20px 0;
|
||||||
|
margin-top: 65px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.box {
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 16px;
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
|
||||||
|
padding: 24px 16px;
|
||||||
|
flex: 1 1 0;
|
||||||
|
min-width: 260px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: fit-content;
|
||||||
|
min-height: 600px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.step-title {
|
||||||
|
color: #b23c3c;
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 1.1em;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
letter-spacing: 0.02em;
|
||||||
|
transition: color 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.step-title.completed {
|
||||||
|
color: #008000 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Service section */
|
||||||
|
.service-list {
|
||||||
|
flex: 1;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-item {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 1.1em;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-item .del {
|
||||||
|
cursor: pointer;
|
||||||
|
color: #b23c3c;
|
||||||
|
margin-left: 8px;
|
||||||
|
font-size: 1.2em;
|
||||||
|
transition: color 0.3s ease, opacity 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-item .del:hover {
|
||||||
|
color: #ff0000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-item .del.disabled {
|
||||||
|
color: #ccc;
|
||||||
|
cursor: not-allowed;
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-item .del.disabled:hover {
|
||||||
|
color: #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-item .price {
|
||||||
|
font-weight: bold;
|
||||||
|
color: #b23c3c;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Service count indicator */
|
||||||
|
.service-count-info {
|
||||||
|
font-size: 0.85em;
|
||||||
|
color: #888;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
text-align: center;
|
||||||
|
padding: 4px 8px;
|
||||||
|
background: #f8f9fa;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-count-info.single {
|
||||||
|
color: #ff8c00;
|
||||||
|
background: #fff3e0;
|
||||||
|
border: 1px solid #ffcc80;
|
||||||
|
}
|
||||||
|
|
||||||
|
.total {
|
||||||
|
border-top: 1px solid #eee;
|
||||||
|
margin-top: auto;
|
||||||
|
padding-top: 16px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
font-size: 1.1em;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.total .price {
|
||||||
|
color: #b23c3c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.total small {
|
||||||
|
font-weight: normal;
|
||||||
|
color: #888;
|
||||||
|
font-size: 0.9em;
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Calendar section */
|
||||||
|
.calendar-box {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.calendar-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.calendar-header button {
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
font-size: 1.2em;
|
||||||
|
cursor: pointer;
|
||||||
|
color: #b23c3c;
|
||||||
|
padding: 0 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.calendar-table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.calendar-table th,
|
||||||
|
.calendar-table td {
|
||||||
|
width: 2em;
|
||||||
|
height: 2em;
|
||||||
|
padding: 2px;
|
||||||
|
font-size: 1em;
|
||||||
|
border-radius: 50%;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background 0.15s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.calendar-table th {
|
||||||
|
color: #b23c3c;
|
||||||
|
font-weight: 500;
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.calendar-table td.selected {
|
||||||
|
background: #b23c3c;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.calendar-table td.today {
|
||||||
|
border: 1.5px solid #b23c3c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.calendar-table td:not(.selected):hover {
|
||||||
|
background: #f5eaea;
|
||||||
|
}
|
||||||
|
|
||||||
|
.calendar-table td.disabled {
|
||||||
|
color: #ccc;
|
||||||
|
pointer-events: none;
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Time slots */
|
||||||
|
.time-slots {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 8px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.time-btn {
|
||||||
|
flex: 1 0 30%;
|
||||||
|
min-width: 80px;
|
||||||
|
padding: 8px 0;
|
||||||
|
border: 1px solid #b23c3c;
|
||||||
|
border-radius: 20px;
|
||||||
|
background: #fff;
|
||||||
|
color: #b23c3c;
|
||||||
|
font-size: 1em;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background 0.15s, color 0.15s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.time-btn.selected,
|
||||||
|
.time-btn:active {
|
||||||
|
background: #b23c3c;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.time-btn:disabled {
|
||||||
|
color: #ccc;
|
||||||
|
border-color: #eee;
|
||||||
|
background: #f5f5f5;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.person-count {
|
||||||
|
margin-top: 12px;
|
||||||
|
font-size: 0.98em;
|
||||||
|
color: #888;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Form section */
|
||||||
|
.form-group {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-group label {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-group input,
|
||||||
|
.form-group textarea {
|
||||||
|
width: 100%;
|
||||||
|
padding: 8px 10px;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
border-radius: 6px;
|
||||||
|
font-size: 1em;
|
||||||
|
resize: none;
|
||||||
|
transition: border-color 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-group textarea {
|
||||||
|
min-height: 60px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkbox-group {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 18px;
|
||||||
|
font-size: 0.98em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkbox-group input[type="checkbox"] {
|
||||||
|
margin-right: 8px;
|
||||||
|
accent-color: #b23c3c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.submit-btn {
|
||||||
|
width: 100%;
|
||||||
|
padding: 14px 0;
|
||||||
|
background: #ddd;
|
||||||
|
color: #888;
|
||||||
|
border: none;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-size: 1.1em;
|
||||||
|
font-weight: bold;
|
||||||
|
cursor: not-allowed;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.submit-btn.step-progress {
|
||||||
|
background: linear-gradient(45deg, #ddd, #bbb);
|
||||||
|
color: #666;
|
||||||
|
font-size: 0.95em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.submit-btn.ready {
|
||||||
|
background: #b23c3c;
|
||||||
|
color: #fff;
|
||||||
|
cursor: pointer;
|
||||||
|
animation: pulse 2s infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes pulse {
|
||||||
|
0% { transform: scale(1); }
|
||||||
|
50% { transform: scale(1.02); }
|
||||||
|
100% { transform: scale(1); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Phone message styles (common.js PhoneValidator용) */
|
||||||
|
.phone-message {
|
||||||
|
font-size: 12px;
|
||||||
|
margin-top: 5px;
|
||||||
|
padding: 4px 8px;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-weight: 500;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.phone-message.error {
|
||||||
|
color: #ff0000;
|
||||||
|
background-color: #ffebee;
|
||||||
|
border: 1px solid #ffcdd2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.phone-message.warning {
|
||||||
|
color: #ff8c00;
|
||||||
|
background-color: #fff3e0;
|
||||||
|
border: 1px solid #ffcc80;
|
||||||
|
}
|
||||||
|
|
||||||
|
.phone-message.success {
|
||||||
|
color: #008000;
|
||||||
|
background-color: #f1f8e9;
|
||||||
|
border: 1px solid #c8e6c9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.phone-message.info {
|
||||||
|
color: #2196f3;
|
||||||
|
background-color: #e3f2fd;
|
||||||
|
border: 1px solid #90caf9;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Birth date message styles */
|
||||||
|
.birth-date-message {
|
||||||
|
font-size: 12px;
|
||||||
|
margin-top: 5px;
|
||||||
|
padding: 4px 8px;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-weight: 500;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.birth-date-message.error {
|
||||||
|
color: #ff0000;
|
||||||
|
background-color: #ffebee;
|
||||||
|
border: 1px solid #ffcdd2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.birth-date-message.warning {
|
||||||
|
color: #ff8c00;
|
||||||
|
background-color: #fff3e0;
|
||||||
|
border: 1px solid #ffcc80;
|
||||||
|
}
|
||||||
|
|
||||||
|
.birth-date-message.success {
|
||||||
|
color: #008000;
|
||||||
|
background-color: #f1f8e9;
|
||||||
|
border: 1px solid #c8e6c9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.birth-date-message.info {
|
||||||
|
color: #2196f3;
|
||||||
|
background-color: #e3f2fd;
|
||||||
|
border: 1px solid #90caf9;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Disabled calendar cell - 강화된 스타일 */
|
||||||
|
.calendar-table td.disabled {
|
||||||
|
color: #ccc;
|
||||||
|
cursor: not-allowed;
|
||||||
|
pointer-events: none;
|
||||||
|
background: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.calendar-table td.disabled:hover {
|
||||||
|
background: none !important;
|
||||||
|
cursor: not-allowed !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flatpickr-calendar {
|
||||||
|
max-width: 320px;
|
||||||
|
margin: 0 auto;
|
||||||
|
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
.flatpickr-day.disabled {
|
||||||
|
color: #ccc !important;
|
||||||
|
background: #f8f9fa;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flatpickr-day.today {
|
||||||
|
background: #007bff;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flatpickr-day.selected {
|
||||||
|
background: #28a745;
|
||||||
|
border-color: #28a745;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Responsive Design */
|
||||||
|
@media (max-width: 1199.98px) {
|
||||||
|
.reservation-container {
|
||||||
|
max-width: 960px !important;
|
||||||
|
gap: 16px;
|
||||||
|
padding: 20px 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.box {
|
||||||
|
padding: 20px 14px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 991.98px) {
|
||||||
|
.reservation-container {
|
||||||
|
max-width: 720px !important;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 24px;
|
||||||
|
height: auto;
|
||||||
|
padding: 20px 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.box {
|
||||||
|
min-height: unset;
|
||||||
|
min-width: unset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 767.98px) {
|
||||||
|
.reservation-container {
|
||||||
|
max-width: 540px !important;
|
||||||
|
padding: 15px;
|
||||||
|
gap: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.box {
|
||||||
|
padding: 16px 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.calendar-table th,
|
||||||
|
.calendar-table td {
|
||||||
|
width: 1.8em;
|
||||||
|
height: 1.8em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.time-btn {
|
||||||
|
min-width: 70px;
|
||||||
|
font-size: 0.95em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 575.98px) {
|
||||||
|
.reservation-container {
|
||||||
|
max-width: 100% !important;
|
||||||
|
padding: 10px;
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.box {
|
||||||
|
padding: 16px 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.calendar-table th,
|
||||||
|
.calendar-table td {
|
||||||
|
width: 1.5em;
|
||||||
|
height: 1.5em;
|
||||||
|
font-size: 0.9em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.time-btn {
|
||||||
|
min-width: 60px;
|
||||||
|
font-size: 0.9em;
|
||||||
|
padding: 6px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.step-title {
|
||||||
|
font-size: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-item {
|
||||||
|
font-size: 1em;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
|
||||||
font-weight: 600;
|
|
||||||
color: #A73439;
|
|
||||||
}
|
|
||||||
|
|
||||||
.procedure-area:after {
|
|
||||||
display: block;
|
|
||||||
visibility: hidden;
|
|
||||||
height: 0;
|
|
||||||
font-size: 0;
|
|
||||||
clear: both;
|
|
||||||
content: "";
|
|
||||||
}
|
|
||||||
|
|
||||||
.selected-procedure{
|
|
||||||
margin-top:20px;
|
|
||||||
position:relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.selected-procedure .selt_info_wrap .info {
|
|
||||||
top: 0.7rem;
|
|
||||||
width: 9.5em;
|
|
||||||
padding-top: 0.3em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.selt_info_wrap .info {
|
|
||||||
position: absolute;
|
|
||||||
top: 0.2rem;
|
|
||||||
right: 0.2rem;
|
|
||||||
width: 8.5em;
|
|
||||||
padding-right: 1rem;
|
|
||||||
padding-top: 0.2em;
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
.selt_info_wrap .info button{
|
|
||||||
border:none;
|
|
||||||
background-color:#fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.real_price {
|
|
||||||
font-family: 'Campton', Sans-serif;
|
|
||||||
font-weight: 600;
|
|
||||||
color: #A73439;
|
|
||||||
}
|
|
||||||
|
|
||||||
.selected-procedure .selt_info_wrap {
|
|
||||||
padding: 0.8rem 0;
|
|
||||||
z-index:0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.selt_info_wrap {
|
|
||||||
position: relative;
|
|
||||||
min-height: 2.5rem;
|
|
||||||
background-color:#fff;
|
|
||||||
border:1px solid #eee;
|
|
||||||
}
|
|
||||||
|
|
||||||
.selected-procedure .selt_info_wrap .selt {
|
|
||||||
padding-right: 9.5em;
|
|
||||||
padding-left: 1rem;
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
border-radius: 18px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.selt_info_wrap .selt {
|
.info-box {
|
||||||
padding-top: 0.3em;
|
flex: 1 1 300px;
|
||||||
padding-right: 8.5em;
|
min-width: 240px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.total-price-area .total {
|
.info-title {
|
||||||
position: relative;
|
font-size: 1.7em;
|
||||||
background-color: #e6e6e6;
|
font-weight: 700;
|
||||||
padding: 25px 25px 60px;
|
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;
|
||||||
|
color: #e74c3c;
|
||||||
|
background: #fef2f2;
|
||||||
|
border: 1px solid #fecaca;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 10px 14px;
|
||||||
|
margin-bottom: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.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;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 1.1em;
|
||||||
|
margin-bottom: 18px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.total-price-area .total .txt_sub {
|
.total-row .total-label {
|
||||||
color: #222222;
|
color: #888;
|
||||||
font-size: 2rem;
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
.total-price-area .total .right strong {
|
|
||||||
font-size: 22px;
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.total-price-area .total-price-txt {
|
.total-row .total-price {
|
||||||
font-family: 'Campton', Sans-serif;
|
font-weight: bold;
|
||||||
font-weight: 600;
|
color: #b23c3c;
|
||||||
color: #A73439;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.total-price-area .total .bs-txt {
|
.reserve-btn {
|
||||||
position: absolute;
|
width: 100%;
|
||||||
bottom: 17px;
|
padding: 14px 0;
|
||||||
right: 25px;
|
background: #b23c3c;
|
||||||
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;
|
color: #fff;
|
||||||
|
border: none;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-size: 1.1em;
|
||||||
|
font-weight: bold;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background 0.15s;
|
||||||
}
|
}
|
||||||
|
|
||||||
.img-content{
|
.reserve-btn:disabled {
|
||||||
background-color: #eee;
|
background: #ddd;
|
||||||
|
color: #888;
|
||||||
|
cursor: not-allowed;
|
||||||
}
|
}
|
||||||
|
|
||||||
.img-area{
|
.desc-section {
|
||||||
padding-top: 70px;
|
margin-top: 36px;
|
||||||
padding-bottom: 200px;
|
padding: 0 32px;
|
||||||
text-align:center;
|
}
|
||||||
|
|
||||||
|
.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 {
|
||||||
|
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%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -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%;}
|
html,
|
||||||
.project_wrap .same aside ul li{margin-bottom: 0.5rem; margin-top: 0px;}
|
body {
|
||||||
.project_wrap .same aside .first {padding-top: 1rem; padding-bottom: 1rem;}
|
height: 100vh;
|
||||||
.project_wrap .same aside .nonactive {border: 1px solid #d8d8d8; background-color: #f9f9fb;}
|
margin: 0;
|
||||||
.project_wrap .same aside .active {border: 1px solid #d8d8d8; color: #a73439; background-color: rgba(118, 35, 47, 0); border-left: 2px solid #a73439;}
|
padding: 0;
|
||||||
.project_wrap .same aside ul a{padding-left: 10px;}
|
font-family: 'Pretendard', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', sans-serif;
|
||||||
.project_wrap .same main {width: 60%; padding-top: 7%;}
|
background: #f8f9fa;
|
||||||
.project_wrap .same main ul{padding-top: 2%; width:102%;}
|
color: #1a1a1a;
|
||||||
.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; }
|
overflow-x: hidden;
|
||||||
.event-card-list > li { margin-bottom: 70px; opacity: 1;}
|
font-size: 16px;
|
||||||
.event-card-list .event-card { display: block; position: relative; width: 775px; height: 196px; padding-right: 10px; margin-left: auto; overflow: hidden;}
|
line-height: 1.6;
|
||||||
.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 {
|
.container {
|
||||||
position: relative;
|
max-width: 1280px;
|
||||||
display: block;
|
width: 100%;
|
||||||
border-radius: 1rem;
|
margin: 0 auto;
|
||||||
padding: 1rem;
|
min-height: calc(100vh - 300px);
|
||||||
}
|
|
||||||
.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;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-direction: column;
|
||||||
|
gap: 1.5rem;
|
||||||
}
|
}
|
||||||
.border-b {
|
|
||||||
border-bottom: 1px solid #ddd;
|
/* 상단 헤더 영역 */
|
||||||
height:5%;
|
.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;
|
||||||
}
|
}
|
||||||
.txt_num {
|
|
||||||
font-family: 'Campton', Sans-serif;
|
.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;
|
||||||
|
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;
|
font-weight: 600;
|
||||||
color: #A73439;
|
border-left: 4px solid #C60B24;
|
||||||
}
|
}
|
||||||
.card_otxt .ab_cont {
|
|
||||||
|
/* 메인 콘텐츠 영역 */
|
||||||
|
.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;
|
position: absolute;
|
||||||
right: 1rem;
|
top: 12px;
|
||||||
top: 3.4rem;
|
right: 12px;
|
||||||
width: 8.5em;
|
background: rgba(107, 114, 128, 0.9);
|
||||||
text-align: right;
|
color: #fff;
|
||||||
|
padding: 4px 12px;
|
||||||
|
border-radius: 20px;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
font-weight: 600;
|
||||||
|
z-index: 2;
|
||||||
}
|
}
|
||||||
.card_otxt .fix_cont {
|
|
||||||
padding-right: 11.5rem;
|
.event-img {
|
||||||
|
width: 340px;
|
||||||
|
min-width: 280px;
|
||||||
|
background: #f3f4f6;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
.card_otxt .fix_cont p {
|
|
||||||
|
.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;
|
margin-bottom: 0;
|
||||||
word-break: keep-all;
|
|
||||||
}
|
}
|
||||||
.mb3{margin-bottom: 3rem;}
|
|
||||||
.mt70{margin-top: 70%;}
|
|
||||||
|
|
||||||
|
/* 로딩 및 에러 메시지 */
|
||||||
/* 반응형 - 모바일 */
|
.loading {
|
||||||
@media only screen and (max-width:768px){
|
text-align: center;
|
||||||
/* main_img */
|
padding: 2rem;
|
||||||
.project_wrap .same main .content5 { padding-bottom:0; }
|
color: #6b7280;
|
||||||
.project_wrap .same main .main_img .text_box > div { width:100%; }
|
font-size: 0.9375rem;
|
||||||
.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; }
|
|
||||||
.project_wrap .same main {width: 100%;}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.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;
|
||||||
|
}
|
||||||
|
|
||||||
|
.category-link {
|
||||||
|
text-align: center;
|
||||||
|
padding: 0.75rem 0.5rem;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.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);
|
||||||
|
}
|
||||||
|
|
||||||
|
.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,255 @@
|
|||||||
|
* {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Quill 에디터 본문 */
|
||||||
|
.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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Quill 에디터 특수 클래스 */
|
||||||
|
.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,412 @@
|
|||||||
|
* {
|
||||||
|
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: 109 KiB |
BIN
src/main/resources/static/image/equip/20260313/온다리프팅(Body).jpg
Normal file
|
After Width: | Height: | Size: 162 KiB |
BIN
src/main/resources/static/image/equip/20260313/울핏.jpg
Normal file
|
After Width: | Height: | Size: 117 KiB |
BIN
src/main/resources/static/image/equip/20260313/튠바디.jpg
Normal file
|
After Width: | Height: | Size: 131 KiB |
BIN
src/main/resources/static/image/equip/20260313/티타늄리프팅(Body).jpg
Normal file
|
After Width: | Height: | Size: 125 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: 389 KiB |
598
src/main/resources/static/js/makeReservation.js
Normal file
@@ -0,0 +1,598 @@
|
|||||||
|
// 휴일(완전 휴무) 설정
|
||||||
|
const disabledSpecificDates = [
|
||||||
|
'2025-12-25', // 크리스마스
|
||||||
|
'2026-01-01' // 신정
|
||||||
|
];
|
||||||
|
|
||||||
|
// 단축 진료일 (15:30까지, 점심시간 없음)
|
||||||
|
const shortWorkingDates = [
|
||||||
|
'2025-12-24', // 크리스마스 이브
|
||||||
|
'2025-12-31' // 연말
|
||||||
|
];
|
||||||
|
|
||||||
|
// 점심시간 (14:00 ~ 15:00)
|
||||||
|
const lunchTimeStart = 1400; // 14:00
|
||||||
|
const lunchTimeEnd = 1500; // 15:00
|
||||||
|
|
||||||
|
// 날짜가 휴무일인지 확인
|
||||||
|
function isDateDisabled(date) {
|
||||||
|
const dateStr = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`;
|
||||||
|
return disabledSpecificDates.includes(dateStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 단축 근무일인지 확인
|
||||||
|
function isShortWorkingDate(date) {
|
||||||
|
const dateStr = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`;
|
||||||
|
return shortWorkingDates.includes(dateStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 점심시간인지 확인 (월화수목금만 해당)
|
||||||
|
function isLunchTime(timeStr) {
|
||||||
|
const timeNum = parseInt(timeStr.replace(':', '')); // "14:30" -> 1430
|
||||||
|
return timeNum >= lunchTimeStart && timeNum < lunchTimeEnd;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 생년월일 검증 클래스
|
||||||
|
class BirthDateValidator {
|
||||||
|
constructor(inputId, options = {}) {
|
||||||
|
this.inputElement = document.getElementById(inputId);
|
||||||
|
this.messageElement = null;
|
||||||
|
this.options = {
|
||||||
|
showMessage: true,
|
||||||
|
realTimeValidation: true,
|
||||||
|
minAge: 0,
|
||||||
|
maxAge: 150,
|
||||||
|
format: 'YYYYMMDD',
|
||||||
|
allowFuture: false,
|
||||||
|
onValidationChange: null,
|
||||||
|
...options
|
||||||
|
};
|
||||||
|
|
||||||
|
if (this.inputElement && this.options.showMessage) {
|
||||||
|
this.createMessageElement();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.inputElement && this.options.realTimeValidation) {
|
||||||
|
this.bindEvents();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
createMessageElement() {
|
||||||
|
this.messageElement = document.createElement('div');
|
||||||
|
this.messageElement.className = 'birth-date-message';
|
||||||
|
this.messageElement.style.display = 'none';
|
||||||
|
this.inputElement.parentNode.insertBefore(this.messageElement, this.inputElement.nextSibling);
|
||||||
|
}
|
||||||
|
|
||||||
|
bindEvents() {
|
||||||
|
this.inputElement.addEventListener('input', () => {
|
||||||
|
this.inputElement.value = this.inputElement.value.replace(/[^0-9]/g, '');
|
||||||
|
this.validateAndShowMessage();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.inputElement.addEventListener('blur', () => {
|
||||||
|
this.validateAndShowMessage();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.inputElement.addEventListener('keydown', (e) => {
|
||||||
|
if ([8, 9, 46, 37, 38, 39, 40].includes(e.keyCode)) return;
|
||||||
|
if ((e.keyCode < 48 || e.keyCode > 57) && (e.keyCode < 96 || e.keyCode > 105)) {
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
validateBirthDate(dateStr) {
|
||||||
|
if (!dateStr) return { valid: false, message: '생년월일을 입력해주세요.' };
|
||||||
|
|
||||||
|
let cleanDate = dateStr.replace(/[^0-9]/g, '');
|
||||||
|
if (cleanDate.length !== 8) {
|
||||||
|
return { valid: false, message: '생년월일은 8자리 숫자로 입력해주세요. (예: 19900115)' };
|
||||||
|
}
|
||||||
|
|
||||||
|
const year = parseInt(cleanDate.slice(0, 4));
|
||||||
|
const month = parseInt(cleanDate.slice(4, 6));
|
||||||
|
const day = parseInt(cleanDate.slice(6, 8));
|
||||||
|
|
||||||
|
const currentYear = new Date().getFullYear();
|
||||||
|
const minYear = currentYear - this.options.maxAge;
|
||||||
|
const maxYear = currentYear - this.options.minAge;
|
||||||
|
|
||||||
|
if (year < minYear || year > maxYear) {
|
||||||
|
return { valid: false, message: `출생연도는 ${minYear}년부터 ${maxYear}년 사이여야 합니다.` };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (month < 1 || month > 12) return { valid: false, message: '월은 01부터 12까지 입력 가능합니다.' };
|
||||||
|
if (day < 1 || day > 31) return { valid: false, message: '일은 01부터 31까지 입력 가능합니다.' };
|
||||||
|
|
||||||
|
const date = new Date(year, month - 1, day);
|
||||||
|
const isValidDate = date.getFullYear() === year && date.getMonth() === month - 1 && date.getDate() === day;
|
||||||
|
|
||||||
|
if (!isValidDate) return { valid: false, message: '존재하지 않는 날짜입니다.' };
|
||||||
|
if (!this.options.allowFuture && date > new Date()) return { valid: false, message: '미래 날짜는 입력할 수 없습니다.' };
|
||||||
|
|
||||||
|
return { valid: true, message: '올바른 생년월일입니다.' };
|
||||||
|
}
|
||||||
|
|
||||||
|
validateAndShowMessage() {
|
||||||
|
const result = this.validateBirthDate(this.inputElement.value);
|
||||||
|
if (this.messageElement) {
|
||||||
|
this.messageElement.textContent = result.message;
|
||||||
|
this.messageElement.className = `birth-date-message ${result.valid ? 'success' : 'error'}`;
|
||||||
|
this.messageElement.style.display = 'block';
|
||||||
|
}
|
||||||
|
if (typeof this.options.onValidationChange === 'function') {
|
||||||
|
this.options.onValidationChange(result, this.inputElement.value);
|
||||||
|
}
|
||||||
|
return result.valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
isValid() {
|
||||||
|
return this.validateBirthDate(this.inputElement.value).valid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 전역 변수
|
||||||
|
let birthDateValidator;
|
||||||
|
let selectedTreatments = [];
|
||||||
|
let selectedDate = null;
|
||||||
|
let selectedTime = null;
|
||||||
|
let selectedYear, selectedMonth;
|
||||||
|
|
||||||
|
// DOM 요소
|
||||||
|
const calendarTitle = document.getElementById('calendar-title');
|
||||||
|
const calendarTable = document.getElementById('calendar-table');
|
||||||
|
const timeSlots = document.getElementById('time-slots');
|
||||||
|
const personCount = document.getElementById('person-count');
|
||||||
|
const form = document.getElementById('reserve-form');
|
||||||
|
const agree = document.getElementById('agree');
|
||||||
|
const submitBtn = document.getElementById('submit-btn');
|
||||||
|
const step02Title = document.getElementById('step02-title');
|
||||||
|
const step03Title = document.getElementById('step03-title');
|
||||||
|
|
||||||
|
// 진료시간 설정 (점심시간 제외)
|
||||||
|
const times_mon_wed_fri = [
|
||||||
|
"10:00","10:30","11:00","11:30","12:00","12:30","13:00","13:30",
|
||||||
|
"15:00","15:30","16:00","16:30","17:00","17:30","18:00","18:30"
|
||||||
|
];
|
||||||
|
|
||||||
|
const times_tue_thu = [
|
||||||
|
"10:00","10:30","11:00","11:30","12:00","12:30","13:00","13:30",
|
||||||
|
"15:00","15:30","16:00","16:30","17:00","17:30","18:00","18:30","19:00","19:30"
|
||||||
|
];
|
||||||
|
|
||||||
|
const times_sat_short = [
|
||||||
|
"10:00","10:30","11:00","11:30","12:00","12:30","13:00","13:30",
|
||||||
|
"14:00","14:30","15:00","15:30"
|
||||||
|
];
|
||||||
|
|
||||||
|
// 시술 관리 함수들
|
||||||
|
function removeService(el) {
|
||||||
|
const serviceItems = document.querySelectorAll('.service-item');
|
||||||
|
if (serviceItems.length <= 1) {
|
||||||
|
alert('최소 1개의 시술은 선택되어 있어야 합니다.');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const serviceName = el.closest('.service-item').querySelector('span:first-child').textContent;
|
||||||
|
if (!confirm(`'${serviceName}' 시술을 삭제하시겠습니까?`)) return false;
|
||||||
|
|
||||||
|
el.closest('.service-item').remove();
|
||||||
|
updateTotalPrice();
|
||||||
|
updateServiceCount();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateTotalPrice() {
|
||||||
|
const serviceItems = document.querySelectorAll('.service-item');
|
||||||
|
let totalPrice = 0;
|
||||||
|
serviceItems.forEach(item => {
|
||||||
|
const priceText = item.querySelector('.price').textContent;
|
||||||
|
totalPrice += parseInt(priceText.replace(/[^0-9]/g, '')) || 0;
|
||||||
|
});
|
||||||
|
document.getElementById('total-price').textContent = totalPrice.toLocaleString() + '원';
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateServiceCount() {
|
||||||
|
const serviceItems = document.querySelectorAll('.service-item');
|
||||||
|
const count = serviceItems.length;
|
||||||
|
const info = document.getElementById('service-count-info');
|
||||||
|
info.textContent = `선택된 시술: ${count}개${count === 1 ? ' (최소 필수)' : ''}`;
|
||||||
|
info.className = count === 1 ? 'service-count-info single' : 'service-count-info';
|
||||||
|
|
||||||
|
serviceItems.forEach(item => {
|
||||||
|
const delBtn = item.querySelector('.del');
|
||||||
|
if (count <= 1) {
|
||||||
|
delBtn.className = 'del disabled';
|
||||||
|
delBtn.title = '최소 1개의 시술은 필요합니다';
|
||||||
|
} else {
|
||||||
|
delBtn.className = 'del';
|
||||||
|
delBtn.title = '삭제';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 캘린더 렌더링 (일요일 + 공휴일만 휴무)
|
||||||
|
function renderCalendar(year, month) {
|
||||||
|
selectedYear = year;
|
||||||
|
selectedMonth = month;
|
||||||
|
calendarTitle.textContent = `${year}.${String(month + 1).padStart(2, '0')}`;
|
||||||
|
|
||||||
|
const firstDay = new Date(year, month, 1);
|
||||||
|
const lastDay = new Date(year, month + 1, 0);
|
||||||
|
const todayDate = new Date();
|
||||||
|
todayDate.setHours(0, 0, 0, 0);
|
||||||
|
|
||||||
|
let html = '<thead><tr>';
|
||||||
|
['일','월','화','수','목','금','토'].forEach(d => html += `<th>${d}</th>`);
|
||||||
|
html += '</tr></thead><tbody><tr>';
|
||||||
|
|
||||||
|
for(let i = 0; i < firstDay.getDay(); i++) html += '<td class="disabled"></td>';
|
||||||
|
|
||||||
|
for(let d = 1; d <= lastDay.getDate(); d++) {
|
||||||
|
const dateObj = new Date(year, month, d);
|
||||||
|
let classes = [];
|
||||||
|
|
||||||
|
const isPastDate = dateObj < todayDate;
|
||||||
|
const isSunday = dateObj.getDay() === 0;
|
||||||
|
const isHoliday = isDateDisabled(dateObj);
|
||||||
|
|
||||||
|
if(dateObj.toDateString() === new Date().toDateString()) classes.push('today');
|
||||||
|
if(selectedDate && dateObj.toDateString() === selectedDate.toDateString()) classes.push('selected');
|
||||||
|
|
||||||
|
if(isPastDate || isSunday || isHoliday) classes.push('disabled');
|
||||||
|
|
||||||
|
const clickHandler = (isPastDate || isSunday || isHoliday) ?
|
||||||
|
'' : `onclick="selectDate(${year},${month},${d})"`;
|
||||||
|
html += `<td class="${classes.join(' ')}" ${clickHandler}>${d}</td>`;
|
||||||
|
|
||||||
|
if((firstDay.getDay() + d) % 7 === 0 && d !== lastDay.getDate()) html += '</tr><tr>';
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = lastDay.getDay(); i < 6; i++) {
|
||||||
|
html += '<td class="disabled"></td>';
|
||||||
|
}
|
||||||
|
html += '</tr></tbody>';
|
||||||
|
calendarTable.innerHTML = html;
|
||||||
|
checkForm();
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectDate(y, m, d) {
|
||||||
|
const tempDate = new Date(y, m, d);
|
||||||
|
const todayDate = new Date();
|
||||||
|
todayDate.setHours(0, 0, 0, 0);
|
||||||
|
|
||||||
|
if (tempDate < todayDate) {
|
||||||
|
alert('과거 날짜는 선택할 수 없습니다.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tempDate.getDay() === 0) {
|
||||||
|
alert('일요일은 휴무일입니다.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isDateDisabled(tempDate)) {
|
||||||
|
alert('해당 날짜는 휴무일입니다.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
selectedDate = tempDate;
|
||||||
|
renderCalendar(y, m);
|
||||||
|
renderTimeSlots();
|
||||||
|
checkForm();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 월 이동
|
||||||
|
document.getElementById('prev-month').onclick = function() {
|
||||||
|
selectedMonth === 0 ? (selectedYear--, selectedMonth = 11) : selectedMonth--;
|
||||||
|
renderCalendar(selectedYear, selectedMonth);
|
||||||
|
};
|
||||||
|
|
||||||
|
document.getElementById('next-month').onclick = function() {
|
||||||
|
selectedMonth === 11 ? (selectedYear++, selectedMonth = 0) : selectedMonth++;
|
||||||
|
renderCalendar(selectedYear, selectedMonth);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 시간 슬롯 렌더링 (점심시간 제외 + 특수일 처리)
|
||||||
|
function renderTimeSlots() {
|
||||||
|
if (!selectedDate) {
|
||||||
|
timeSlots.innerHTML = '';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const dayOfWeek = selectedDate.getDay();
|
||||||
|
if (dayOfWeek === 0 || isDateDisabled(selectedDate)) {
|
||||||
|
timeSlots.innerHTML = '';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let slotArr;
|
||||||
|
if (isShortWorkingDate(selectedDate)) {
|
||||||
|
slotArr = times_sat_short; // 12/24, 12/31: 토요일과 동일
|
||||||
|
} else if ([1, 3, 5].includes(dayOfWeek)) { // 월수금
|
||||||
|
slotArr = times_mon_wed_fri;
|
||||||
|
} else if ([2, 4].includes(dayOfWeek)) { // 화목
|
||||||
|
slotArr = times_tue_thu;
|
||||||
|
} else if (dayOfWeek === 6) { // 토
|
||||||
|
slotArr = times_sat_short;
|
||||||
|
} else {
|
||||||
|
timeSlots.innerHTML = '';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const now = new Date();
|
||||||
|
const todayDate = new Date(now.getFullYear(), now.getMonth(), now.getDate());
|
||||||
|
const isToday = selectedDate.toDateString() === todayDate.toDateString();
|
||||||
|
|
||||||
|
let html = '';
|
||||||
|
slotArr.forEach(t => {
|
||||||
|
let isDisabled = false;
|
||||||
|
if (isToday) {
|
||||||
|
const currentTime = now.getHours() * 100 + now.getMinutes();
|
||||||
|
const [hour, minute] = t.split(':').map(Number);
|
||||||
|
if (hour * 100 + minute <= currentTime) isDisabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const selectedClass = selectedTime === t && !isDisabled ? ' selected' : '';
|
||||||
|
const disabledAttr = isDisabled ? 'disabled' : '';
|
||||||
|
html += `<button type="button" class="time-btn${selectedClass}${isDisabled ? ' disabled' : ''}"
|
||||||
|
${isDisabled ? '' : `onclick="selectTimeAndCall('${t}', this)"`} ${disabledAttr}>${t}</button>`;
|
||||||
|
});
|
||||||
|
|
||||||
|
timeSlots.innerHTML = html;
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectTimeAndCall(t, el) {
|
||||||
|
const now = new Date();
|
||||||
|
const todayDate = new Date(now.getFullYear(), now.getMonth(), now.getDate());
|
||||||
|
const isToday = selectedDate.toDateString() === todayDate.toDateString();
|
||||||
|
|
||||||
|
if (isToday) {
|
||||||
|
const currentTime = now.getHours() * 100 + now.getMinutes();
|
||||||
|
const [hour, minute] = t.split(':').map(Number);
|
||||||
|
if (hour * 100 + minute <= currentTime) {
|
||||||
|
alert('지난 시간은 선택할 수 없습니다.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
selectedTime = t;
|
||||||
|
renderTimeSlots();
|
||||||
|
if (el) {
|
||||||
|
document.querySelectorAll('.time-btn').forEach(btn => btn.classList.remove('active'));
|
||||||
|
el.classList.add('active');
|
||||||
|
}
|
||||||
|
onClickTime(getSelectedDateStr(), t);
|
||||||
|
checkForm();
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSelectedDateStr() {
|
||||||
|
if (!selectedDate) return '';
|
||||||
|
return selectedDate.getFullYear() +
|
||||||
|
String(selectedDate.getMonth() + 1).padStart(2, '0') +
|
||||||
|
String(selectedDate.getDate()).padStart(2, '0');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 폼 검증
|
||||||
|
function checkForm() {
|
||||||
|
const name = document.getElementById('customer-name').value.trim();
|
||||||
|
const phone = document.getElementById('customer-phone').value.trim();
|
||||||
|
const birthDate = document.getElementById('birthDate').value.trim();
|
||||||
|
|
||||||
|
const phoneValid = phone.match(/^01[0-9]{8,9}$/) ||
|
||||||
|
(typeof PhoneValidator !== 'undefined' && PhoneValidator.isValid?.('customer-phone'));
|
||||||
|
const birthDateValid = birthDate.match(/^\d{8}$/) ||
|
||||||
|
(birthDateValidator?.isValid?.());
|
||||||
|
|
||||||
|
const conditions = {
|
||||||
|
date: !!selectedDate,
|
||||||
|
time: !!selectedTime,
|
||||||
|
name: !!name,
|
||||||
|
phone: !!phoneValid,
|
||||||
|
birthDate: !!birthDateValid,
|
||||||
|
agree: agree.checked
|
||||||
|
};
|
||||||
|
|
||||||
|
const valid = Object.values(conditions).every(Boolean);
|
||||||
|
submitBtn.disabled = !valid;
|
||||||
|
|
||||||
|
updateStepStatus(conditions);
|
||||||
|
updateButtonText(conditions);
|
||||||
|
|
||||||
|
submitBtn.className = valid ? 'submit-btn ready' :
|
||||||
|
selectedDate ? 'submit-btn step-progress' : 'submit-btn';
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateStepStatus(conditions) {
|
||||||
|
step02Title.textContent = (conditions.date && conditions.time) ? 'STEP 02. 예약 시간 선택 ✓' : 'STEP 02. 예약 시간 선택';
|
||||||
|
step02Title.className = (conditions.date && conditions.time) ? 'step-title completed' : 'step-title';
|
||||||
|
|
||||||
|
step03Title.textContent = (conditions.name && conditions.phone && conditions.birthDate && conditions.agree) ?
|
||||||
|
'STEP 03. 고객정보 ✓' : 'STEP 03. 고객정보';
|
||||||
|
step03Title.className = (conditions.name && conditions.phone && conditions.birthDate && conditions.agree) ?
|
||||||
|
'step-title completed' : 'step-title';
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateButtonText(conditions) {
|
||||||
|
if (!conditions.date) return submitBtn.textContent = '📅 예약 날짜를 선택해주세요';
|
||||||
|
if (!conditions.time) return submitBtn.textContent = '⏰ 예약 시간을 선택해주세요';
|
||||||
|
if (!conditions.name) return submitBtn.textContent = '👤 고객명을 입력해주세요';
|
||||||
|
if (!conditions.birthDate) return submitBtn.textContent = '📅 생년월일을 올바르게 입력해주세요';
|
||||||
|
if (!conditions.phone) return submitBtn.textContent = '📱 연락처를 올바르게 입력해주세요';
|
||||||
|
if (!conditions.agree) return submitBtn.textContent = '✅ 개인정보 동의를 체크해주세요';
|
||||||
|
submitBtn.textContent = '🎉 시술 예약하기';
|
||||||
|
}
|
||||||
|
|
||||||
|
// 초기화
|
||||||
|
const today = new Date();
|
||||||
|
selectedYear = today.getFullYear();
|
||||||
|
selectedMonth = today.getMonth();
|
||||||
|
|
||||||
|
form.addEventListener('input', (e) => {
|
||||||
|
if (e.target.id !== 'customer-phone' && e.target.id !== 'birthDate') setTimeout(checkForm, 10);
|
||||||
|
});
|
||||||
|
agree.addEventListener('change', checkForm);
|
||||||
|
|
||||||
|
form.onsubmit = function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
if (!selectedDate || !selectedTime) {
|
||||||
|
alert('예약 날짜와 시간을 선택해 주세요.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!birthDateValidator?.isValid()) {
|
||||||
|
alert('올바른 생년월일을 입력해 주세요.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fn_reservation();
|
||||||
|
};
|
||||||
|
|
||||||
|
// AJAX 함수들 (기존 그대로)
|
||||||
|
function fn_reservation() {
|
||||||
|
let formData = new FormData();
|
||||||
|
if (selectedDate) {
|
||||||
|
formData.append('SELECTED_DATE', `${selectedDate.getFullYear()}-${String(selectedDate.getMonth() + 1).padStart(2, '0')}-${String(selectedDate.getDate()).padStart(2, '0')}`);
|
||||||
|
}
|
||||||
|
if (selectedTime) formData.append('TIME', selectedTime);
|
||||||
|
formData.append('CATEGORY_DIV_CD', typeof category_div_cd !== 'undefined' ? category_div_cd : '');
|
||||||
|
formData.append('CATEGORY_NO', typeof category_no !== 'undefined' ? category_no : '');
|
||||||
|
formData.append('POST_NO', typeof post_no !== 'undefined' ? post_no : '');
|
||||||
|
formData.append('NAME', document.getElementById('customer-name').value);
|
||||||
|
formData.append('BIRTH_DATE', document.getElementById('birthDate').value);
|
||||||
|
formData.append('PHONE_NUMBER', document.getElementById('customer-phone').value);
|
||||||
|
formData.append('ETC', document.getElementById('customer-req').value);
|
||||||
|
formData.append('TREATMENT_INFOS', JSON.stringify(selectedTreatments));
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
url: encodeURI('/webservice/insertReservation.do'),
|
||||||
|
data: formData,
|
||||||
|
dataType: 'json',
|
||||||
|
processData: false,
|
||||||
|
contentType: false,
|
||||||
|
type: 'POST',
|
||||||
|
async: true,
|
||||||
|
success: function(data) {
|
||||||
|
if (data.msgCode == '0') {
|
||||||
|
alert('예약이 완료되었습니다.');
|
||||||
|
location.href = "/webevent/selectListWebEventIntro.do";
|
||||||
|
} else {
|
||||||
|
modalEvent.danger("조회 오류", data.msgDesc);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: function() {
|
||||||
|
modalEvent.danger("조회 오류", "조회 중 오류가 발생하였습니다. 잠시후 다시시도하십시오.");
|
||||||
|
},
|
||||||
|
beforeSend: function() { $(".loading-image-layer").show(); },
|
||||||
|
complete: function() { $(".loading-image-layer").hide(); }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function fn_SelectReservation(category_div_cd, category_no, post_no, procedure_id) {
|
||||||
|
let formData = new FormData();
|
||||||
|
formData.append('CATEGORY_DIV_CD', category_div_cd);
|
||||||
|
formData.append('CATEGORY_NO', category_no);
|
||||||
|
formData.append('POST_NO', post_no);
|
||||||
|
formData.append('PROCEDURE_ID', procedure_id);
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
url: encodeURI('/webservice/selectReservation.do'),
|
||||||
|
data: formData,
|
||||||
|
dataType: 'json',
|
||||||
|
processData: false,
|
||||||
|
contentType: false,
|
||||||
|
type: 'POST',
|
||||||
|
async: true,
|
||||||
|
success: function(data) {
|
||||||
|
if (data.msgCode == '0') {
|
||||||
|
const serviceList = document.getElementById('service-list');
|
||||||
|
serviceList.innerHTML = '';
|
||||||
|
let totalprice = 0;
|
||||||
|
selectedTreatments = [];
|
||||||
|
|
||||||
|
if (data.reservation?.length > 0) {
|
||||||
|
data.reservation.forEach(item => {
|
||||||
|
let price = item.DISCOUNT_PRICE ?? item.PRICE ?? 0;
|
||||||
|
totalprice += Number(price);
|
||||||
|
|
||||||
|
selectedTreatments.push({
|
||||||
|
MU_TREATMENT_ID: item.MU_TREATMENT_ID,
|
||||||
|
TREATMENT_NAME: item.TREATMENT_NAME,
|
||||||
|
TREATMENT_PROCEDURE_NAME: item.TREATMENT_PROCEDURE_NAME,
|
||||||
|
MU_TREATMENT_PROCEDURE_ID: item.MU_TREATMENT_PROCEDURE_ID
|
||||||
|
});
|
||||||
|
|
||||||
|
const div = document.createElement('div');
|
||||||
|
div.className = 'service-item';
|
||||||
|
div.innerHTML = `
|
||||||
|
<span>${item.TREATMENT_PROCEDURE_NAME}</span>
|
||||||
|
<span>
|
||||||
|
${item.DISCOUNT_PRICE != null ? `<span style="text-decoration:line-through; color:#bbb; font-size:0.95em; margin-right:6px;">${(item.PRICE || 0).toLocaleString()}원</span>` : ''}
|
||||||
|
<span class="price">${Number(price).toLocaleString()}원</span>
|
||||||
|
<span class="del" title="삭제" onclick="removeService(this)">×</span>
|
||||||
|
</span>
|
||||||
|
`;
|
||||||
|
serviceList.appendChild(div);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
document.getElementById('total-price').textContent = totalprice.toLocaleString() + '원';
|
||||||
|
updateServiceCount();
|
||||||
|
} else {
|
||||||
|
modalEvent.danger("조회 오류", data.msgDesc);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: function() {
|
||||||
|
modalEvent.danger("조회 오류", "조회 중 오류가 발생하였습니다. 잠시후 다시시도하십시오.");
|
||||||
|
},
|
||||||
|
beforeSend: function() { $(".loading-image-layer").show(); },
|
||||||
|
complete: function() { $(".loading-image-layer").hide(); }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function onClickTime(selectedDateStr, time) {
|
||||||
|
let formData = new FormData();
|
||||||
|
formData.append('SELECTED_DATE', selectedDateStr);
|
||||||
|
formData.append('TIME', time);
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
url: encodeURI('/webservice/selectReservationCnt.do'),
|
||||||
|
data: formData,
|
||||||
|
dataType: 'json',
|
||||||
|
processData: false,
|
||||||
|
contentType: false,
|
||||||
|
type: 'POST',
|
||||||
|
async: true,
|
||||||
|
success: function(data) {
|
||||||
|
personCount.textContent = data.msgCode == '0' && data.rows?.RES_CNT !== undefined ?
|
||||||
|
data.rows.RES_CNT : '-';
|
||||||
|
},
|
||||||
|
error: function() {
|
||||||
|
personCount.textContent = '-';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 문서 준비 완료
|
||||||
|
$(document).ready(function() {
|
||||||
|
// Validator 초기화
|
||||||
|
try {
|
||||||
|
birthDateValidator = new BirthDateValidator('birthDate', {
|
||||||
|
showMessage: true,
|
||||||
|
realTimeValidation: true,
|
||||||
|
onValidationChange: () => setTimeout(checkForm, 10)
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
console.error('BirthDateValidator init error:', e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 초기 캘린더 및 시술 로드
|
||||||
|
const today = new Date();
|
||||||
|
let initDate = new Date(today.getFullYear(), today.getMonth(), today.getDate());
|
||||||
|
while (initDate.getDay() === 0 || isDateDisabled(initDate)) {
|
||||||
|
initDate.setDate(initDate.getDate() + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderCalendar(today.getFullYear(), today.getMonth());
|
||||||
|
fn_SelectReservation(category_div_cd, category_no, post_no, procedure_id);
|
||||||
|
|
||||||
|
setTimeout(checkForm, 500);
|
||||||
|
});
|
||||||
@@ -21,10 +21,10 @@ function showBackgroundMask() {
|
|||||||
if (mask) {
|
if (mask) {
|
||||||
mask.classList.add('active');
|
mask.classList.add('active');
|
||||||
}
|
}
|
||||||
|
|
||||||
// body에 popup-open 클래스 추가 (스크롤 비활성화 및 블러 효과)
|
// body에 popup-open 클래스 추가 (스크롤 비활성화 및 블러 효과)
|
||||||
document.body.classList.add('popup-open');
|
document.body.classList.add('popup-open');
|
||||||
|
|
||||||
console.log('Background mask activated');
|
console.log('Background mask activated');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -34,10 +34,10 @@ function hideBackgroundMask() {
|
|||||||
if (mask) {
|
if (mask) {
|
||||||
mask.classList.remove('active');
|
mask.classList.remove('active');
|
||||||
}
|
}
|
||||||
|
|
||||||
// body에서 popup-open 클래스 제거
|
// body에서 popup-open 클래스 제거
|
||||||
document.body.classList.remove('popup-open');
|
document.body.classList.remove('popup-open');
|
||||||
|
|
||||||
console.log('Background mask deactivated');
|
console.log('Background mask deactivated');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,14 +50,14 @@ const cont1Urls = [
|
|||||||
// 필요시 추가
|
// 필요시 추가
|
||||||
];
|
];
|
||||||
|
|
||||||
const bullet1 = ['다이어트약','지방분해주사']
|
const bullet1 = ['다이어트약', '쉬다주사']
|
||||||
|
|
||||||
const useCont1Loop = bullet1.length > 2; // slidesPerView(1.3)보다 많을 때만 loop
|
const useCont1Loop = bullet1.length > 2; // slidesPerView(1.3)보다 많을 때만 loop
|
||||||
const cont1Swiper = new Swiper('.cont1_swiper', {
|
const cont1Swiper = new Swiper('.cont1_swiper', {
|
||||||
loop: useCont1Loop,
|
loop: useCont1Loop,
|
||||||
slidesPerView: 'auto',
|
slidesPerView: 'auto',
|
||||||
spaceBetween: 10,
|
spaceBetween: 10,
|
||||||
autoplay : {
|
autoplay: {
|
||||||
disableOnInteraction: false,
|
disableOnInteraction: false,
|
||||||
},
|
},
|
||||||
pagination: {
|
pagination: {
|
||||||
@@ -69,22 +69,22 @@ const cont1Swiper = new Swiper('.cont1_swiper', {
|
|||||||
},
|
},
|
||||||
on: {
|
on: {
|
||||||
init: function () {
|
init: function () {
|
||||||
document.querySelectorAll('.cont1_swiper .swiper-slide').forEach(function(slide, idx) {
|
document.querySelectorAll('.cont1_swiper .swiper-slide').forEach(function (slide, idx) {
|
||||||
slide.style.cursor = 'pointer';
|
slide.style.cursor = 'pointer';
|
||||||
slide.setAttribute('data-url', cont1Urls[idx] || cont1Urls[0]);
|
slide.setAttribute('data-url', cont1Urls[idx] || cont1Urls[0]);
|
||||||
slide.addEventListener('click', function() {
|
slide.addEventListener('click', function () {
|
||||||
const url = slide.getAttribute('data-url');
|
const url = slide.getAttribute('data-url');
|
||||||
if(url) window.open(url, '_blank');
|
if (url) window.open(url, '_blank');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
slideChange: function () {
|
slideChange: function () {
|
||||||
document.querySelectorAll('.cont1_swiper .swiper-slide').forEach(function(slide, idx) {
|
document.querySelectorAll('.cont1_swiper .swiper-slide').forEach(function (slide, idx) {
|
||||||
slide.style.cursor = 'pointer';
|
slide.style.cursor = 'pointer';
|
||||||
slide.setAttribute('data-url', cont1Urls[idx] || cont1Urls[0]);
|
slide.setAttribute('data-url', cont1Urls[idx] || cont1Urls[0]);
|
||||||
slide.onclick = function() {
|
slide.onclick = function () {
|
||||||
const url = slide.getAttribute('data-url');
|
const url = slide.getAttribute('data-url');
|
||||||
if(url) window.open(url, '_blank');
|
if (url) window.open(url, '_blank');
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -95,19 +95,21 @@ const cont1Swiper = new Swiper('.cont1_swiper', {
|
|||||||
* content2 스와이퍼
|
* content2 스와이퍼
|
||||||
************************************************/
|
************************************************/
|
||||||
const cont2Urls = [
|
const cont2Urls = [
|
||||||
'https://diet.madeu.co.kr/webservice/selectServiceIntro.do?categoryNo=3', // 첫 번째 슬라이드 URL
|
'https://diet.madeu.co.kr/webservice/selectServiceDetailIntro.do?categoryDivCd=01&categoryNo=3&postNo=9',
|
||||||
'https://diet.madeu.co.kr/webservice/selectServiceIntro.do?categoryNo=3' // 두 번째 슬라이드 URL
|
'https://diet.madeu.co.kr/webservice/selectServiceDetailIntro.do?categoryDivCd=01&categoryNo=3&postNo=2',
|
||||||
|
'https://diet.madeu.co.kr/webservice/selectServiceDetailIntro.do?categoryDivCd=01&categoryNo=3&postNo=10',
|
||||||
|
'https://diet.madeu.co.kr/webservice/selectServiceDetailIntro.do?categoryDivCd=01&categoryNo=3&postNo=1'
|
||||||
// 필요시 추가
|
// 필요시 추가
|
||||||
];
|
];
|
||||||
|
|
||||||
const bullet2 = ['울핏','튠바디']
|
const bullet2 = ['온다리프팅', '튠바디', '티타늄리프팅', '울핏']
|
||||||
|
|
||||||
const useCont2Loop = bullet2.length > 2; // slidesPerView(1.3)보다 많을 때만 loop
|
const useCont2Loop = bullet2.length > 2; // slidesPerView(1.3)보다 많을 때만 loop
|
||||||
const cont2Swiper = new Swiper('.cont2_swiper', {
|
const cont2Swiper = new Swiper('.cont2_swiper', {
|
||||||
loop: useCont2Loop,
|
loop: useCont2Loop,
|
||||||
slidesPerView: 'auto',
|
slidesPerView: 'auto',
|
||||||
spaceBetween: 10,
|
spaceBetween: 10,
|
||||||
autoplay : {
|
autoplay: {
|
||||||
disableOnInteraction: false,
|
disableOnInteraction: false,
|
||||||
},
|
},
|
||||||
pagination: {
|
pagination: {
|
||||||
@@ -119,22 +121,22 @@ const cont2Swiper = new Swiper('.cont2_swiper', {
|
|||||||
},
|
},
|
||||||
on: {
|
on: {
|
||||||
init: function () {
|
init: function () {
|
||||||
document.querySelectorAll('.cont2_swiper .swiper-slide').forEach(function(slide, idx) {
|
document.querySelectorAll('.cont2_swiper .swiper-slide').forEach(function (slide, idx) {
|
||||||
slide.style.cursor = 'pointer';
|
slide.style.cursor = 'pointer';
|
||||||
slide.setAttribute('data-url', cont2Urls[idx] || cont2Urls[0]);
|
slide.setAttribute('data-url', cont2Urls[idx] || cont2Urls[0]);
|
||||||
slide.addEventListener('click', function() {
|
slide.addEventListener('click', function () {
|
||||||
const url = slide.getAttribute('data-url');
|
const url = slide.getAttribute('data-url');
|
||||||
if(url) window.open(url, '_blank');
|
if (url) window.open(url, '_blank');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
slideChange: function () {
|
slideChange: function () {
|
||||||
document.querySelectorAll('.cont2_swiper .swiper-slide').forEach(function(slide, idx) {
|
document.querySelectorAll('.cont2_swiper .swiper-slide').forEach(function (slide, idx) {
|
||||||
slide.style.cursor = 'pointer';
|
slide.style.cursor = 'pointer';
|
||||||
slide.setAttribute('data-url', cont2Urls[idx] || cont2Urls[0]);
|
slide.setAttribute('data-url', cont2Urls[idx] || cont2Urls[0]);
|
||||||
slide.onclick = function() {
|
slide.onclick = function () {
|
||||||
const url = slide.getAttribute('data-url');
|
const url = slide.getAttribute('data-url');
|
||||||
if(url) window.open(url, '_blank');
|
if (url) window.open(url, '_blank');
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -144,7 +146,7 @@ const cont2Swiper = new Swiper('.cont2_swiper', {
|
|||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* 팝업 리스트 조회 (마스킹 기능 추가)
|
* 팝업 리스트 조회 (마스킹 기능 추가)
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
function fn_selectListWebPopupJson(){
|
function fn_selectListWebPopupJson() {
|
||||||
let formData = new FormData();
|
let formData = new FormData();
|
||||||
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
@@ -155,12 +157,12 @@ function fn_selectListWebPopupJson(){
|
|||||||
contentType: false,
|
contentType: false,
|
||||||
type: 'POST',
|
type: 'POST',
|
||||||
async: true,
|
async: true,
|
||||||
success: function(data){
|
success: function (data) {
|
||||||
if(data.msgCode=='0'){
|
if (data.msgCode == '0') {
|
||||||
let cookiedata = document.cookie;
|
let cookiedata = document.cookie;
|
||||||
if (cookiedata.indexOf("popup=done") < 0) {
|
if (cookiedata.indexOf("popup=done") < 0) {
|
||||||
$('.popup').addClass('open');
|
$('.popup').addClass('open');
|
||||||
|
|
||||||
// *** 배경 마스킹 활성화 추가 ***
|
// *** 배경 마스킹 활성화 추가 ***
|
||||||
showBackgroundMask();
|
showBackgroundMask();
|
||||||
|
|
||||||
@@ -168,20 +170,20 @@ function fn_selectListWebPopupJson(){
|
|||||||
if (0 < totalCount) {
|
if (0 < totalCount) {
|
||||||
let popupContentList = $('#popupContentList');
|
let popupContentList = $('#popupContentList');
|
||||||
let popupTabList = $('#popupTabList');
|
let popupTabList = $('#popupTabList');
|
||||||
|
|
||||||
popupContentList.empty();
|
popupContentList.empty();
|
||||||
popupTabList.empty();
|
popupTabList.empty();
|
||||||
|
|
||||||
for (let i = 0; i < Math.min(data.rows.length, 5); i++) {
|
for (let i = 0; i < Math.min(data.rows.length, 5); i++) {
|
||||||
let isActive = i === 0 ? ' active' : '';
|
let isActive = i === 0 ? ' active' : '';
|
||||||
const isMobile = window.innerWidth <= 768;
|
const isMobile = window.innerWidth <= 768;
|
||||||
const imgPath = isMobile ? (data.rows[i].m_filePath || data.rows[i].filePath) : data.rows[i].filePath;
|
const imgPath = isMobile ? (data.rows[i].m_filePath || data.rows[i].filePath) : data.rows[i].filePath;
|
||||||
|
|
||||||
// 탭 콘텐츠 생성
|
// 탭 콘텐츠 생성
|
||||||
let contentHTML = '';
|
let contentHTML = '';
|
||||||
contentHTML += '<div role="tabpanel" class="tab-pane' + isActive + '" id="content' + (i+1) + '">';
|
contentHTML += '<div role="tabpanel" class="tab-pane' + isActive + '" id="content' + (i + 1) + '">';
|
||||||
contentHTML += '<a href="' + data.rows[i].url + '" target="_blank" rel="noopener">';
|
contentHTML += '<a href="' + data.rows[i].url + '" target="_blank" rel="noopener">';
|
||||||
contentHTML += '<img src="' + CDN_URL + imgPath + '" alt="event_con' + (i+1) + '" />';
|
contentHTML += '<img src="' + CDN_URL + imgPath + '" alt="event_con' + (i + 1) + '" />';
|
||||||
contentHTML += '</a>';
|
contentHTML += '</a>';
|
||||||
contentHTML += '</div>';
|
contentHTML += '</div>';
|
||||||
popupContentList.append(contentHTML);
|
popupContentList.append(contentHTML);
|
||||||
@@ -189,7 +191,7 @@ function fn_selectListWebPopupJson(){
|
|||||||
// 탭 리스트 생성 (data-toggle 제거하고 클릭 이벤트 직접 처리)
|
// 탭 리스트 생성 (data-toggle 제거하고 클릭 이벤트 직접 처리)
|
||||||
let tabHTML = '';
|
let tabHTML = '';
|
||||||
tabHTML += '<li role="presentation"' + (isActive ? ' class="active"' : '') + '>';
|
tabHTML += '<li role="presentation"' + (isActive ? ' class="active"' : '') + '>';
|
||||||
tabHTML += '<a href="#content' + (i+1) + '" role="tab" id="contentTitle' + (i+1) + '" data-target="content' + (i+1) + '">';
|
tabHTML += '<a href="#content' + (i + 1) + '" role="tab" id="contentTitle' + (i + 1) + '" data-target="content' + (i + 1) + '">';
|
||||||
tabHTML += fn_addBrAfterFirstWord(data.rows[i].title);
|
tabHTML += fn_addBrAfterFirstWord(data.rows[i].title);
|
||||||
tabHTML += '</a>';
|
tabHTML += '</a>';
|
||||||
tabHTML += '</li>';
|
tabHTML += '</li>';
|
||||||
@@ -200,25 +202,25 @@ function fn_selectListWebPopupJson(){
|
|||||||
setupTabEvents();
|
setupTabEvents();
|
||||||
setupPopupCloseEvents();
|
setupPopupCloseEvents();
|
||||||
}
|
}
|
||||||
}else{
|
} else {
|
||||||
$('.popup').removeClass('open');
|
$('.popup').removeClass('open');
|
||||||
hideBackgroundMask(); // 추가
|
hideBackgroundMask(); // 추가
|
||||||
}
|
}
|
||||||
}else if('-2' == data.msgCode){
|
} else if ('-2' == data.msgCode) {
|
||||||
modalEvent.danger("로그인 오류", data.msgDesc, function(){
|
modalEvent.danger("로그인 오류", data.msgDesc, function () {
|
||||||
fn_leftFormAction('/weblogin/logout.do');
|
fn_leftFormAction('/weblogin/logout.do');
|
||||||
});
|
});
|
||||||
}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();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -226,15 +228,15 @@ function fn_selectListWebPopupJson(){
|
|||||||
|
|
||||||
// 탭 이벤트 설정 함수 추가
|
// 탭 이벤트 설정 함수 추가
|
||||||
function setupTabEvents() {
|
function setupTabEvents() {
|
||||||
$('#popupTabList a[role="tab"]').off('click').on('click', function(e) {
|
$('#popupTabList a[role="tab"]').off('click').on('click', function (e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
const targetId = $(this).data('target');
|
const targetId = $(this).data('target');
|
||||||
|
|
||||||
// 모든 탭과 콘텐츠에서 active 클래스 제거
|
// 모든 탭과 콘텐츠에서 active 클래스 제거
|
||||||
$('#popupTabList li').removeClass('active');
|
$('#popupTabList li').removeClass('active');
|
||||||
$('#popupContentList .tab-pane').removeClass('active');
|
$('#popupContentList .tab-pane').removeClass('active');
|
||||||
|
|
||||||
// 클릭된 탭과 해당 콘텐츠에 active 클래스 추가
|
// 클릭된 탭과 해당 콘텐츠에 active 클래스 추가
|
||||||
$(this).parent('li').addClass('active');
|
$(this).parent('li').addClass('active');
|
||||||
$('#' + targetId).addClass('active');
|
$('#' + targetId).addClass('active');
|
||||||
@@ -249,7 +251,7 @@ function setupPopupCloseEvents() {
|
|||||||
// 기존 이벤트 리스너 복제본 생성하여 교체
|
// 기존 이벤트 리스너 복제본 생성하여 교체
|
||||||
const newCloseBtn = closeBtn.cloneNode(true);
|
const newCloseBtn = closeBtn.cloneNode(true);
|
||||||
closeBtn.parentNode.replaceChild(newCloseBtn, closeBtn);
|
closeBtn.parentNode.replaceChild(newCloseBtn, closeBtn);
|
||||||
|
|
||||||
// 새로운 이벤트 리스너 추가
|
// 새로운 이벤트 리스너 추가
|
||||||
newCloseBtn.addEventListener('click', function () {
|
newCloseBtn.addEventListener('click', function () {
|
||||||
//체크박스 확인
|
//체크박스 확인
|
||||||
@@ -259,7 +261,7 @@ function setupPopupCloseEvents() {
|
|||||||
setCookie('done', 1);
|
setCookie('done', 1);
|
||||||
} else {
|
} else {
|
||||||
$('.popup').removeClass('open');
|
$('.popup').removeClass('open');
|
||||||
hideBackgroundMask();
|
hideBackgroundMask();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -280,9 +282,9 @@ function fn_addBrAfterFirstWord(input) {
|
|||||||
function setCookie(value, expiredays) {
|
function setCookie(value, expiredays) {
|
||||||
let todayDate = new Date();
|
let todayDate = new Date();
|
||||||
todayDate.setDate(todayDate.getDate() + expiredays);
|
todayDate.setDate(todayDate.getDate() + expiredays);
|
||||||
document.cookie = "popup=" + escape( value ) + "; path=/; expires=" + todayDate.toGMTString() + ";";
|
document.cookie = "popup=" + escape(value) + "; path=/; expires=" + todayDate.toGMTString() + ";";
|
||||||
$('.popup').removeClass('open');
|
$('.popup').removeClass('open');
|
||||||
|
|
||||||
// *** 배경 마스킹 제거 추가 ***
|
// *** 배경 마스킹 제거 추가 ***
|
||||||
hideBackgroundMask();
|
hideBackgroundMask();
|
||||||
}
|
}
|
||||||
@@ -290,10 +292,10 @@ function setCookie(value, expiredays) {
|
|||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* 메인 배너 리스트 조회
|
* 메인 배너 리스트 조회
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
function fn_selectListWebMainBannerTypeAJson(){
|
function fn_selectListWebMainBannerTypeAJson() {
|
||||||
let formData = new FormData();
|
let formData = new FormData();
|
||||||
formData.append('bannerType', 'DT');
|
formData.append('bannerType', 'DT');
|
||||||
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: encodeURI('/webmainbanner/selectListWebMainBanner.do'),
|
url: encodeURI('/webmainbanner/selectListWebMainBanner.do'),
|
||||||
data: formData,
|
data: formData,
|
||||||
@@ -302,8 +304,8 @@ function fn_selectListWebMainBannerTypeAJson(){
|
|||||||
contentType: false,
|
contentType: false,
|
||||||
type: 'POST',
|
type: 'POST',
|
||||||
async: true,
|
async: true,
|
||||||
success: function(data){
|
success: function (data) {
|
||||||
if(data.msgCode=='0'){
|
if (data.msgCode == '0') {
|
||||||
let totalCount = data.rows.length;
|
let totalCount = data.rows.length;
|
||||||
if (0 < totalCount) {
|
if (0 < totalCount) {
|
||||||
let listHTML = '';
|
let listHTML = '';
|
||||||
@@ -316,8 +318,8 @@ function fn_selectListWebMainBannerTypeAJson(){
|
|||||||
// 이미지와 링크를 a 태그로 감싸기 (url 파라미터 사용)
|
// 이미지와 링크를 a 태그로 감싸기 (url 파라미터 사용)
|
||||||
listHTML += '<div class="swiper-slide" style="background:' + backgroundColor + ';" aria-label="' + currentAriaLabel + '">';
|
listHTML += '<div class="swiper-slide" style="background:' + backgroundColor + ';" aria-label="' + currentAriaLabel + '">';
|
||||||
listHTML += ' <a href="' + data.rows[i].url + '" target="_blank" rel="noopener">';
|
listHTML += ' <a href="' + data.rows[i].url + '" target="_blank" rel="noopener">';
|
||||||
listHTML += ' <img class="pc" src="' + CDN_URL + data.rows[i].webFilePath + '" alt="banner' + (i+1) + '" />';
|
listHTML += ' <img class="pc" src="' + CDN_URL + data.rows[i].webFilePath + '" alt="banner' + (i + 1) + '" />';
|
||||||
listHTML += ' <img class="mb" src="' + CDN_URL + data.rows[i].mobileFilePath + '" alt="banner' + (i+1) + '" />';
|
listHTML += ' <img class="mb" src="' + CDN_URL + data.rows[i].mobileFilePath + '" alt="banner' + (i + 1) + '" />';
|
||||||
listHTML += ' </a>';
|
listHTML += ' </a>';
|
||||||
listHTML += '</div>';
|
listHTML += '</div>';
|
||||||
}
|
}
|
||||||
@@ -330,7 +332,7 @@ function fn_selectListWebMainBannerTypeAJson(){
|
|||||||
const mainBannerSwiper = new Swiper('.main_banner_swiper', {
|
const mainBannerSwiper = new Swiper('.main_banner_swiper', {
|
||||||
loop: useMainBannerLoop,
|
loop: useMainBannerLoop,
|
||||||
slidesPerView: 1,
|
slidesPerView: 1,
|
||||||
autoplay : {
|
autoplay: {
|
||||||
disableOnInteraction: false,
|
disableOnInteraction: false,
|
||||||
},
|
},
|
||||||
pagination: {
|
pagination: {
|
||||||
@@ -351,7 +353,7 @@ function fn_selectListWebMainBannerTypeAJson(){
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
///////// swiper-pagination-bullet 넓이 동적 조정 /////////
|
///////// swiper-pagination-bullet 넓이 동적 조정 /////////
|
||||||
function adjustBulletWidth() {
|
function adjustBulletWidth() {
|
||||||
const bullets = document.querySelectorAll('.main_banner_pagination .swiper-pagination-bullet');
|
const bullets = document.querySelectorAll('.main_banner_pagination .swiper-pagination-bullet');
|
||||||
const paginationWidth = 490;
|
const paginationWidth = 490;
|
||||||
@@ -363,43 +365,43 @@ function fn_selectListWebMainBannerTypeAJson(){
|
|||||||
}
|
}
|
||||||
|
|
||||||
///////// 활성화된 swiper-pagination-bullet 업데이트 /////////
|
///////// 활성화된 swiper-pagination-bullet 업데이트 /////////
|
||||||
function updateActiveBullets(activeIndex) {
|
function updateActiveBullets(activeIndex) {
|
||||||
const bullets = document.querySelectorAll('.mainbannerpagination .swiper-pagination-bullet');
|
const bullets = document.querySelectorAll('.mainbannerpagination .swiper-pagination-bullet');
|
||||||
bullets.forEach(bullet => bullet.classList.remove('swiper-pagination-bullet-active')); // 먼저 모두 제거
|
bullets.forEach(bullet => bullet.classList.remove('swiper-pagination-bullet-active')); // 먼저 모두 제거
|
||||||
if (bullets[activeIndex]) {
|
if (bullets[activeIndex]) {
|
||||||
bullets[activeIndex].classList.add('swiper-pagination-bullet-active'); // 하나만 추가
|
bullets[activeIndex].classList.add('swiper-pagination-bullet-active'); // 하나만 추가
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}else{$("#mainBannerList").empty();}
|
} else { $("#mainBannerList").empty(); }
|
||||||
}else if('-2' == data.msgCode){
|
} else if ('-2' == data.msgCode) {
|
||||||
modalEvent.danger("로그인 오류", data.msgDesc, function(){
|
modalEvent.danger("로그인 오류", data.msgDesc, function () {
|
||||||
fn_leftFormAction('/weblogin/logout.do');
|
fn_leftFormAction('/weblogin/logout.do');
|
||||||
});
|
});
|
||||||
}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_selectListWebMainBannerTypeBJson(){
|
function fn_selectListWebMainBannerTypeBJson() {
|
||||||
let formData = new FormData();
|
let formData = new FormData();
|
||||||
formData.append('bannerType', 'DB');
|
formData.append('bannerType', 'DB');
|
||||||
|
|
||||||
@@ -411,8 +413,8 @@ function fn_selectListWebMainBannerTypeBJson(){
|
|||||||
contentType: false,
|
contentType: false,
|
||||||
type: 'POST',
|
type: 'POST',
|
||||||
async: true,
|
async: true,
|
||||||
success: function(data){
|
success: function (data) {
|
||||||
if(data.msgCode=='0'){
|
if (data.msgCode == '0') {
|
||||||
let totalCount = data.rows.length;
|
let totalCount = data.rows.length;
|
||||||
|
|
||||||
if (0 < totalCount) {
|
if (0 < totalCount) {
|
||||||
@@ -426,8 +428,8 @@ function fn_selectListWebMainBannerTypeBJson(){
|
|||||||
// 이미지와 링크를 a 태그로 감싸기 (url 파라미터 사용)
|
// 이미지와 링크를 a 태그로 감싸기 (url 파라미터 사용)
|
||||||
listHTML += '<div class="swiper-slide" style="background:' + backgroundColor + ';" aria-label="' + currentAriaLabel + '">';
|
listHTML += '<div class="swiper-slide" style="background:' + backgroundColor + ';" aria-label="' + currentAriaLabel + '">';
|
||||||
listHTML += ' <a href="' + data.rows[i].url + '" target="_blank" rel="noopener">';
|
listHTML += ' <a href="' + data.rows[i].url + '" target="_blank" rel="noopener">';
|
||||||
listHTML += ' <img class="pc" src="' + CDN_URL + data.rows[i].webFilePath + '" alt="banner' + (i+1) + '" />';
|
listHTML += ' <img class="pc" src="' + CDN_URL + data.rows[i].webFilePath + '" alt="banner' + (i + 1) + '" />';
|
||||||
listHTML += ' <img class="mb" src="' + CDN_URL + data.rows[i].mobileFilePath + '" alt="banner' + (i+1) + '" />';
|
listHTML += ' <img class="mb" src="' + CDN_URL + data.rows[i].mobileFilePath + '" alt="banner' + (i + 1) + '" />';
|
||||||
listHTML += ' <button class="detail_btn">Detail view ></button>';
|
listHTML += ' <button class="detail_btn">Detail view ></button>';
|
||||||
listHTML += ' </a>';
|
listHTML += ' </a>';
|
||||||
listHTML += '</div>';
|
listHTML += '</div>';
|
||||||
@@ -441,7 +443,7 @@ function fn_selectListWebMainBannerTypeBJson(){
|
|||||||
const subBannerSwiper = new Swiper('.sub_banner_swiper', {
|
const subBannerSwiper = new Swiper('.sub_banner_swiper', {
|
||||||
loop: useSubBannerLoop,
|
loop: useSubBannerLoop,
|
||||||
slidesPerView: 1,
|
slidesPerView: 1,
|
||||||
autoplay : {
|
autoplay: {
|
||||||
disableOnInteraction: false,
|
disableOnInteraction: false,
|
||||||
},
|
},
|
||||||
pagination: {
|
pagination: {
|
||||||
@@ -462,7 +464,7 @@ function fn_selectListWebMainBannerTypeBJson(){
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
///////// swiper-pagination-bullet 넓이 동적 조정 /////////
|
///////// swiper-pagination-bullet 넓이 동적 조정 /////////
|
||||||
function adjustSubBulletWidth() {
|
function adjustSubBulletWidth() {
|
||||||
const bullets = document.querySelectorAll('.sub_banner_pagination .swiper-pagination-bullet');
|
const bullets = document.querySelectorAll('.sub_banner_pagination .swiper-pagination-bullet');
|
||||||
const paginationWidth = 490;
|
const paginationWidth = 490;
|
||||||
@@ -486,24 +488,24 @@ function fn_selectListWebMainBannerTypeBJson(){
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}else{$("#subBannerList").empty();}
|
} else { $("#subBannerList").empty(); }
|
||||||
}else if('-2' == data.msgCode){
|
} else if ('-2' == data.msgCode) {
|
||||||
modalEvent.danger("로그인 오류", data.msgDesc, function(){
|
modalEvent.danger("로그인 오류", data.msgDesc, function () {
|
||||||
fn_leftFormAction('/weblogin/logout.do');
|
fn_leftFormAction('/weblogin/logout.do');
|
||||||
});
|
});
|
||||||
}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();
|
||||||
}
|
}
|
||||||
@@ -513,7 +515,7 @@ function fn_selectListWebMainBannerTypeBJson(){
|
|||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* 인스타그램 피드 리스트 조회 (백엔드 API 사용)
|
* 인스타그램 피드 리스트 조회 (백엔드 API 사용)
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
function fn_selectListWebInstagramJson(){
|
function fn_selectListWebInstagramJson() {
|
||||||
let formData = new FormData();
|
let formData = new FormData();
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: encodeURI('/webinstagram/selectListWebInstagram.do'),
|
url: encodeURI('/webinstagram/selectListWebInstagram.do'),
|
||||||
@@ -523,8 +525,8 @@ function fn_selectListWebInstagramJson(){
|
|||||||
contentType: false,
|
contentType: false,
|
||||||
type: 'POST',
|
type: 'POST',
|
||||||
async: true,
|
async: true,
|
||||||
success: function(data){
|
success: function (data) {
|
||||||
if(data.msgCode=='0'){
|
if (data.msgCode == '0') {
|
||||||
let totalCount = data.rows.length;
|
let totalCount = data.rows.length;
|
||||||
if (0 < totalCount) {
|
if (0 < totalCount) {
|
||||||
let listHTML = '';
|
let listHTML = '';
|
||||||
@@ -535,12 +537,12 @@ function fn_selectListWebInstagramJson(){
|
|||||||
let permalink = data.rows[i].permalink;
|
let permalink = data.rows[i].permalink;
|
||||||
let mediaType = data.rows[i].media_type || '';
|
let mediaType = data.rows[i].media_type || '';
|
||||||
let thumbnailUrl = data.rows[i].thumbnail_url || mediaUrl;
|
let thumbnailUrl = data.rows[i].thumbnail_url || mediaUrl;
|
||||||
listHTML += '<div class="swiper-slide" aria-label="'+currentAriaLabel+'">';
|
listHTML += '<div class="swiper-slide" aria-label="' + currentAriaLabel + '">';
|
||||||
listHTML += ' <a href="'+permalink+'" target="_blank" rel="noopener">';
|
listHTML += ' <a href="' + permalink + '" target="_blank" rel="noopener">';
|
||||||
if (mediaType === 'VIDEO' || mediaType === 'REEL') {
|
if (mediaType === 'VIDEO' || mediaType === 'REEL') {
|
||||||
listHTML += ' <img src="'+thumbnailUrl+'" alt="instagram'+(i+1)+'" />';
|
listHTML += ' <img src="' + thumbnailUrl + '" alt="instagram' + (i + 1) + '" />';
|
||||||
} else {
|
} else {
|
||||||
listHTML += ' <img src="'+mediaUrl+'" alt="instagram'+(i+1)+'" />';
|
listHTML += ' <img src="' + mediaUrl + '" alt="instagram' + (i + 1) + '" />';
|
||||||
}
|
}
|
||||||
listHTML += ' </a>';
|
listHTML += ' </a>';
|
||||||
listHTML += '</div>';
|
listHTML += '</div>';
|
||||||
@@ -549,22 +551,22 @@ function fn_selectListWebInstagramJson(){
|
|||||||
// 커스텀 내비게이션과 연동
|
// 커스텀 내비게이션과 연동
|
||||||
initInstagramCustomNav(data);
|
initInstagramCustomNav(data);
|
||||||
}
|
}
|
||||||
}else if('-2' == data.msgCode){
|
} else if ('-2' == data.msgCode) {
|
||||||
modalEvent.danger("로그인 오류", data.msgDesc, function(){
|
modalEvent.danger("로그인 오류", data.msgDesc, function () {
|
||||||
fn_leftFormAction('/weblogin/logout.do');
|
fn_leftFormAction('/weblogin/logout.do');
|
||||||
});
|
});
|
||||||
}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();
|
||||||
}
|
}
|
||||||
@@ -577,12 +579,12 @@ function fn_selectListWebInstagramJson(){
|
|||||||
function initInstagramCustomNav(data) {
|
function initInstagramCustomNav(data) {
|
||||||
const totalCount = data.rows.length;
|
const totalCount = data.rows.length;
|
||||||
if (totalCount === 0) return;
|
if (totalCount === 0) return;
|
||||||
|
|
||||||
// 썸네일은 최대 3개로 고정
|
// 썸네일은 최대 3개로 고정
|
||||||
const maxThumbs = 3;
|
const maxThumbs = 3;
|
||||||
const showThumbs = Math.min(totalCount, maxThumbs);
|
const showThumbs = Math.min(totalCount, maxThumbs);
|
||||||
let currentActiveIndex = 0; // 현재 활성 인덱스 추적
|
let currentActiveIndex = 0; // 현재 활성 인덱스 추적
|
||||||
|
|
||||||
// 썸네일 버튼 생성 (활성 상태 포함)
|
// 썸네일 버튼 생성 (활성 상태 포함)
|
||||||
function createThumbnails(startIndex = 0) {
|
function createThumbnails(startIndex = 0) {
|
||||||
let thumbsHTML = '';
|
let thumbsHTML = '';
|
||||||
@@ -592,17 +594,17 @@ function initInstagramCustomNav(data) {
|
|||||||
const thumbnailUrl = data.rows[dataIndex].thumbnail_url || mediaUrl;
|
const thumbnailUrl = data.rows[dataIndex].thumbnail_url || mediaUrl;
|
||||||
const isActive = dataIndex === currentActiveIndex ? 'active' : '';
|
const isActive = dataIndex === currentActiveIndex ? 'active' : '';
|
||||||
thumbsHTML += `<div class="custom-swiper-thumb ${isActive}" data-index="${dataIndex}">
|
thumbsHTML += `<div class="custom-swiper-thumb ${isActive}" data-index="${dataIndex}">
|
||||||
<img src="${thumbnailUrl}" alt="thumb${dataIndex+1}" />
|
<img src="${thumbnailUrl}" alt="thumb${dataIndex + 1}" />
|
||||||
</div>`;
|
</div>`;
|
||||||
}
|
}
|
||||||
document.querySelector('.custom-swiper-thumbs').innerHTML = thumbsHTML;
|
document.querySelector('.custom-swiper-thumbs').innerHTML = thumbsHTML;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 초기 썸네일 생성
|
// 초기 썸네일 생성
|
||||||
createThumbnails(0);
|
createThumbnails(0);
|
||||||
|
|
||||||
// Swiper 인스턴스
|
// Swiper 인스턴스
|
||||||
setTimeout(function() {
|
setTimeout(function () {
|
||||||
const instagramSwiper = new Swiper('.instagram_swiper', {
|
const instagramSwiper = new Swiper('.instagram_swiper', {
|
||||||
loop: true,
|
loop: true,
|
||||||
autoplay: {
|
autoplay: {
|
||||||
@@ -619,18 +621,18 @@ function initInstagramCustomNav(data) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
on: {
|
on: {
|
||||||
slideChange: function() {
|
slideChange: function () {
|
||||||
const newIndex = this.realIndex % totalCount;
|
const newIndex = this.realIndex % totalCount;
|
||||||
currentActiveIndex = newIndex; // 활성 인덱스 업데이트
|
currentActiveIndex = newIndex; // 활성 인덱스 업데이트
|
||||||
|
|
||||||
// 콘텐츠가 3개보다 많은 경우 썸네일 순환 업데이트
|
// 콘텐츠가 3개보다 많은 경우 썸네일 순환 업데이트
|
||||||
if (totalCount > maxThumbs) {
|
if (totalCount > maxThumbs) {
|
||||||
// 현재 활성 썸네일이 보이는지 확인
|
// 현재 활성 썸네일이 보이는지 확인
|
||||||
const visibleThumbs = Array.from(document.querySelectorAll('.custom-swiper-thumb'));
|
const visibleThumbs = Array.from(document.querySelectorAll('.custom-swiper-thumb'));
|
||||||
const isActiveVisible = visibleThumbs.some(thumb =>
|
const isActiveVisible = visibleThumbs.some(thumb =>
|
||||||
parseInt(thumb.dataset.index) === currentActiveIndex
|
parseInt(thumb.dataset.index) === currentActiveIndex
|
||||||
);
|
);
|
||||||
|
|
||||||
// 활성 썸네일이 보이지 않으면 썸네일 업데이트
|
// 활성 썸네일이 보이지 않으면 썸네일 업데이트
|
||||||
if (!isActiveVisible) {
|
if (!isActiveVisible) {
|
||||||
updateThumbnailsForIndex(currentActiveIndex);
|
updateThumbnailsForIndex(currentActiveIndex);
|
||||||
@@ -646,41 +648,41 @@ function initInstagramCustomNav(data) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// 좌우 버튼 이벤트
|
// 좌우 버튼 이벤트
|
||||||
document.querySelector('.custom-swiper-btn.prev').onclick = function() {
|
document.querySelector('.custom-swiper-btn.prev').onclick = function () {
|
||||||
instagramSwiper.slidePrev();
|
instagramSwiper.slidePrev();
|
||||||
};
|
};
|
||||||
document.querySelector('.custom-swiper-btn.next').onclick = function() {
|
document.querySelector('.custom-swiper-btn.next').onclick = function () {
|
||||||
instagramSwiper.slideNext();
|
instagramSwiper.slideNext();
|
||||||
};
|
};
|
||||||
|
|
||||||
// 썸네일 클릭 이벤트
|
// 썸네일 클릭 이벤트
|
||||||
document.querySelector('.custom-swiper-thumbs').onclick = function(e) {
|
document.querySelector('.custom-swiper-thumbs').onclick = function (e) {
|
||||||
const thumb = e.target.closest('.custom-swiper-thumb');
|
const thumb = e.target.closest('.custom-swiper-thumb');
|
||||||
if (thumb) {
|
if (thumb) {
|
||||||
const targetIndex = parseInt(thumb.dataset.index);
|
const targetIndex = parseInt(thumb.dataset.index);
|
||||||
instagramSwiper.slideToLoop(targetIndex);
|
instagramSwiper.slideToLoop(targetIndex);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 현재 슬라이드에 맞춰 썸네일 업데이트
|
// 현재 슬라이드에 맞춰 썸네일 업데이트
|
||||||
function updateThumbnailsForIndex(activeIndex) {
|
function updateThumbnailsForIndex(activeIndex) {
|
||||||
if (totalCount <= maxThumbs) return;
|
if (totalCount <= maxThumbs) return;
|
||||||
|
|
||||||
// 현재 활성 인덱스를 중심으로 썸네일 배치
|
// 현재 활성 인덱스를 중심으로 썸네일 배치
|
||||||
let startIndex = activeIndex - Math.floor(maxThumbs / 2);
|
let startIndex = activeIndex - Math.floor(maxThumbs / 2);
|
||||||
if (startIndex < 0) startIndex = totalCount + startIndex;
|
if (startIndex < 0) startIndex = totalCount + startIndex;
|
||||||
|
|
||||||
createThumbnails(startIndex);
|
createThumbnails(startIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 활성 썸네일 표시
|
// 활성 썸네일 표시
|
||||||
function updateCustomThumbActive(activeIdx) {
|
function updateCustomThumbActive(activeIdx) {
|
||||||
document.querySelectorAll('.custom-swiper-thumb').forEach(function(thumb) {
|
document.querySelectorAll('.custom-swiper-thumb').forEach(function (thumb) {
|
||||||
const thumbIndex = parseInt(thumb.dataset.index);
|
const thumbIndex = parseInt(thumb.dataset.index);
|
||||||
thumb.classList.toggle('active', thumbIndex === activeIdx);
|
thumb.classList.toggle('active', thumbIndex === activeIdx);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// 초기 활성 상태 설정
|
// 초기 활성 상태 설정
|
||||||
updateCustomThumbActive(0);
|
updateCustomThumbActive(0);
|
||||||
}, 0);
|
}, 0);
|
||||||
@@ -690,29 +692,29 @@ function initInstagramCustomNav(data) {
|
|||||||
fn_init();
|
fn_init();
|
||||||
|
|
||||||
// 기존 팝업 닫기 버튼 이벤트 (마스킹 기능 추가)
|
// 기존 팝업 닫기 버튼 이벤트 (마스킹 기능 추가)
|
||||||
document.getElementById('btnPopupClose').addEventListener('click',function (){
|
document.getElementById('btnPopupClose').addEventListener('click', function () {
|
||||||
$('.popup').removeClass('open');
|
$('.popup').removeClass('open');
|
||||||
// *** 배경 마스킹 제거 추가 ***
|
// *** 배경 마스킹 제거 추가 ***
|
||||||
hideBackgroundMask();
|
hideBackgroundMask();
|
||||||
});
|
});
|
||||||
|
|
||||||
// 추가 이벤트 리스너들 (새로 추가)
|
// 추가 이벤트 리스너들 (새로 추가)
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
// ESC 키로 팝업 닫기
|
// ESC 키로 팝업 닫기
|
||||||
document.addEventListener('keydown', function(e) {
|
document.addEventListener('keydown', function (e) {
|
||||||
if (e.key === 'Escape' && document.querySelector('.popup.open')) {
|
if (e.key === 'Escape' && document.querySelector('.popup.open')) {
|
||||||
$('.popup').removeClass('open');
|
$('.popup').removeClass('open');
|
||||||
hideBackgroundMask();
|
hideBackgroundMask();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// 마스크 영역 클릭 시 팝업 닫기 (선택사항)
|
// 마스크 영역 클릭 시 팝업 닫기 (선택사항)
|
||||||
const mask = document.querySelector('.popup-background-mask');
|
const mask = document.querySelector('.popup-background-mask');
|
||||||
if (mask) {
|
if (mask) {
|
||||||
mask.addEventListener('click', function() {
|
mask.addEventListener('click', function () {
|
||||||
$('.popup').removeClass('open');
|
$('.popup').removeClass('open');
|
||||||
hideBackgroundMask();
|
hideBackgroundMask();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -188,16 +188,17 @@ 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">
|
||||||
<div class="service-price"><span class="cancel-price">${fn_FormatPrice(service.PRICE)}</span> ${fn_FormatPrice(service.DISCOUNT_PRICE)}</div>
|
${service.PRICE !== service.DISCOUNT_PRICE ? `<span class="cancel-price">${fn_FormatPrice(service.PRICE)}</span> ` : ''}${fn_FormatPrice(service.DISCOUNT_PRICE)}
|
||||||
</div>
|
</div>
|
||||||
`;
|
</div>
|
||||||
});
|
`;
|
||||||
|
});
|
||||||
|
|
||||||
servicesGrid.innerHTML = servicesHtml;
|
servicesGrid.innerHTML = servicesHtml;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,236 +1,314 @@
|
|||||||
/************************************************
|
// 전역 변수
|
||||||
* 초기화
|
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);
|
||||||
formData.append('POST_NO', post_no);
|
formData.append('POST_NO', post_no);
|
||||||
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: encodeURI('/webevent/selectEventDetail.do'),
|
url: encodeURI('/webevent/selectEventDetail.do'),
|
||||||
data: formData,
|
data: formData,
|
||||||
dataType: 'json',
|
dataType: 'json',
|
||||||
processData: false,
|
processData: false,
|
||||||
contentType: false,
|
contentType: false,
|
||||||
type: 'POST',
|
type: 'POST',
|
||||||
async: true,
|
async: true,
|
||||||
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');
|
if (data.rows.PRICE == null || data.rows.PRICE == undefined) {
|
||||||
}else{
|
$('#price').text('0');
|
||||||
$('#startprice').text(data.rows.PRICE.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","));
|
} else {
|
||||||
}
|
$('#price').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($("#checkboxID" + i).is(":checked")){
|
|
||||||
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{
|
|
||||||
listHTML2 += (data.price[i].PRICE).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
|
||||||
}
|
|
||||||
}else{
|
|
||||||
listHTML2 += (data.price[i].DISCOUNT_PRICE).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
|
||||||
}
|
|
||||||
listHTML2 += '</span>원</span>';
|
|
||||||
listHTML2 += ' <button type="button" onclick="fn_nocheck(' + i + ');"><img src="/image/close-btn.png" alt="삭제" width="13px" height="13px"></button>';
|
|
||||||
listHTML2 += ' </div>';
|
|
||||||
listHTML2 += '</li>';
|
|
||||||
$("#selectEvent1").append(listHTML2);
|
|
||||||
var price = $("#price_div1").text().replace(/,/g, "");
|
|
||||||
var 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){
|
|
||||||
discount_price = 0;
|
|
||||||
}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);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}else{
|
|
||||||
listHTML += '<li>';
|
|
||||||
listHTML += '</li>';
|
|
||||||
$(".option_list").html(listHTML);
|
|
||||||
}
|
}
|
||||||
}else{
|
|
||||||
modalEvent.danger("조회 오류", data.msgDesc);
|
|
||||||
}
|
|
||||||
|
|
||||||
},
|
// header 동적 변경
|
||||||
error : function(xhr, status, error) {
|
$('#header-category-nm').text(data.rows.CATEGORY_NM);
|
||||||
modalEvent.danger("조회 오류", "조회 중 오류가 발생하였습니다. 잠시후 다시시도하십시오.");
|
$('#header-title').text(data.rows.TITLE);
|
||||||
},
|
|
||||||
beforeSend:function(){
|
// 해시태그 처리
|
||||||
// 로딩열기
|
var hashtagHtml = '';
|
||||||
$(".loading-image-layer").show();
|
if (data.rows.HASHTAG) {
|
||||||
},
|
var tags = data.rows.HASHTAG.split('#');
|
||||||
complete:function(){
|
tags.forEach(function (tag) {
|
||||||
// 로딩닫기
|
var trimmed = tag.trim();
|
||||||
$(".loading-image-layer").hide();
|
if (trimmed) {
|
||||||
}
|
hashtagHtml += '<span class="hashtag">#' + trimmed + '</span>';
|
||||||
});
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
$('.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 {
|
||||||
|
periodText += window.eventStartDt + ' ~';
|
||||||
|
}
|
||||||
|
periodEl.textContent = periodText;
|
||||||
|
periodEl.style.display = 'block';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 시술 목록 데이터 처리
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function fn_nocheck(num){
|
/****************************************************************************
|
||||||
$("#checkboxID" + num).prop("checked",false);
|
* Choices.js 초기화 및 옵션 업데이트
|
||||||
fn_deleteList(num);
|
****************************************************************************/
|
||||||
|
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 fn_deleteList(num){
|
/****************************************************************************
|
||||||
|
* 총 금액 업데이트 - 개선된 버전
|
||||||
var price = $("#price_div1").text().replace(/,/g, "");
|
****************************************************************************/
|
||||||
var discount_price = $("#liid" + num + " > div.info > span > span").text().replace(/,/g, "");
|
function updateTotalPrice() {
|
||||||
|
if (!procedureChoices) {
|
||||||
price = Number(price) - Number(discount_price);
|
console.log('procedureChoices not initialized');
|
||||||
$("#price_div1").text(price.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","));
|
|
||||||
$("#liid" + num).remove();
|
|
||||||
}
|
|
||||||
|
|
||||||
function fn_moveReservation(category_div, category_no, post_no){
|
|
||||||
let pageMoveForm = document.createElement('form');
|
|
||||||
let obj = document.createElement('input');
|
|
||||||
obj.setAttribute('type', 'hidden');
|
|
||||||
obj.setAttribute('name', 'CATEGORY_DIV_CD');
|
|
||||||
obj.setAttribute('value', "0"+category_div);
|
|
||||||
pageMoveForm.appendChild(obj);
|
|
||||||
|
|
||||||
let obj2 = document.createElement('input');
|
|
||||||
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');
|
|
||||||
obj3.setAttribute('name', 'POST_NO');
|
|
||||||
obj3.setAttribute('value', post_no);
|
|
||||||
pageMoveForm.appendChild(obj3);
|
|
||||||
|
|
||||||
let obj4 = document.getElementsByName('procedure_id');
|
|
||||||
var len = obj4.length;
|
|
||||||
if(len == 0){
|
|
||||||
alert('시술이 선택되지 않았습니다.');
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var value = '';
|
|
||||||
for(var i = 0; i < len; i++){
|
const selectedValues = procedureChoices.getValue(true);
|
||||||
value += obj4[i].getAttribute('value') + '#';
|
console.log('Selected values:', selectedValues);
|
||||||
}
|
|
||||||
|
let total = 0;
|
||||||
let obj5 = document.createElement('input');
|
|
||||||
obj5.setAttribute('type', 'hidden');
|
selectedValues.forEach(value => {
|
||||||
obj5.setAttribute('name', 'PROCEDURE_ID');
|
const item = priceList.find(p => p.MU_TREATMENT_PROCEDURE_ID == value);
|
||||||
obj5.setAttribute('value', value);
|
console.log('Found item for value', value, ':', item);
|
||||||
pageMoveForm.appendChild(obj5);
|
|
||||||
|
if (item) {
|
||||||
pageMoveForm.setAttribute('method', 'post');
|
const basePrice = (item.PRICE || 0) + (item.VAT || 0);
|
||||||
pageMoveForm.setAttribute('action', '/webservice/selectMakeReservation.do');
|
const discountPrice = item.DISCOUNT_PRICE;
|
||||||
document.body.appendChild(pageMoveForm);
|
|
||||||
|
// 할인가가 있고 더 저렴하면 할인가 사용, 아니면 기본가격 사용
|
||||||
pageMoveForm.submit();
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 버튼 클릭했는지 안했는지 확인 class active */
|
/****************************************************************************
|
||||||
var $selectProcedureDiv = $('.select_procedure_div');
|
* 예약 페이지로 이동
|
||||||
$selectProcedureDiv.click(function(e){
|
****************************************************************************/
|
||||||
e.stopPropagation();
|
function fn_moveReservation(category_div, category_no, post_no) {
|
||||||
$selectProcedureDiv.not(this).removeClass('active'); /*remove buttonactive from the others*/
|
if (!procedureChoices) {
|
||||||
$(this).toggleClass('active'); /*toggle current clicked element*/
|
alert('시술 선택 기능이 초기화되지 않았습니다.');
|
||||||
});
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
$(window).on("click", function(){
|
const selectedValues = procedureChoices.getValue(true);
|
||||||
$selectProcedureDiv.removeClass('active');
|
|
||||||
})
|
|
||||||
|
|
||||||
//초기화
|
if (selectedValues.length === 0) {
|
||||||
fn_init();
|
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() {
|
||||||
formData.append('bannerType', 'A');
|
try {
|
||||||
|
const formData = new FormData();
|
||||||
|
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{
|
|
||||||
modalEvent.danger("조회 오류", data.msgDesc);
|
|
||||||
}
|
|
||||||
|
|
||||||
},
|
|
||||||
error : function(xhr, status, error) {
|
|
||||||
modalEvent.danger("조회 오류", "조회 중 오류가 발생하였습니다. 잠시후 다시시도하십시오.");
|
|
||||||
},
|
|
||||||
beforeSend:function(){
|
|
||||||
// 로딩열기
|
|
||||||
$(".loading-image-layer").show();
|
|
||||||
},
|
|
||||||
complete:function(){
|
|
||||||
// 로딩닫기
|
|
||||||
$(".loading-image-layer").hide();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
* 시술 목록 가져오기
|
|
||||||
****************************************************************************/
|
|
||||||
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("조회 오류", "조회 중 오류가 발생하였습니다.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
},
|
async loadEvents(categoryNo) {
|
||||||
error : function(xhr, status, error) {
|
try {
|
||||||
modalEvent.danger("조회 오류", "조회 중 오류가 발생하였습니다. 잠시후 다시시도하십시오.");
|
const formData = new FormData();
|
||||||
},
|
formData.append('category_no', categoryNo);
|
||||||
beforeSend:function(){
|
const data = await this.apiRequest('/webevent/selectListEvent.do', formData);
|
||||||
// 로딩열기
|
|
||||||
$(".loading-image-layer").show();
|
if (data.msgCode === '0') {
|
||||||
},
|
const today = new Date();
|
||||||
complete:function(){
|
today.setHours(0, 0, 0, 0);
|
||||||
// 로딩닫기
|
|
||||||
$(".loading-image-layer").hide();
|
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();
|
||||||
|
} 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 => {
|
||||||
|
const expiredClass = event.isExpired ? ' expired' : '';
|
||||||
|
const expiredBadge = event.isExpired ? '<span class="expired-badge">종료된 이벤트</span>' : '';
|
||||||
|
|
||||||
|
// 이벤트 기간 표시
|
||||||
|
let dateHtml = '';
|
||||||
|
if (event.eventStartDt || event.eventEndDt) {
|
||||||
|
const startStr = event.eventStartDt || '';
|
||||||
|
const endStr = event.eventEndDt || '';
|
||||||
|
if (startStr && endStr) {
|
||||||
|
dateHtml = `<div class="event-date">📅 ${startStr} ~ ${endStr}</div>`;
|
||||||
|
} else if (endStr) {
|
||||||
|
dateHtml = `<div class="event-date">📅 ~ ${endStr}</div>`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return `
|
||||||
|
<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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function fn_moveDetail(category_div, category_no, post_no){
|
const eventManager = new EventManager();
|
||||||
let pageMoveForm = document.createElement('form');
|
|
||||||
let obj = document.createElement('input');
|
|
||||||
obj.setAttribute('type', 'hidden');
|
|
||||||
obj.setAttribute('name', 'CATEGORY_DIV_CD');
|
|
||||||
obj.setAttribute('value', "0"+category_div);
|
|
||||||
pageMoveForm.appendChild(obj);
|
|
||||||
|
|
||||||
let obj2 = document.createElement('input');
|
|
||||||
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');
|
|
||||||
obj3.setAttribute('name', 'POST_NO');
|
|
||||||
obj3.setAttribute('value', post_no);
|
|
||||||
pageMoveForm.appendChild(obj3);
|
|
||||||
|
|
||||||
pageMoveForm.setAttribute('method', 'post');
|
|
||||||
pageMoveForm.setAttribute('action', '/webevent/selectEventDetailIntro.do');
|
|
||||||
document.body.appendChild(pageMoveForm);
|
|
||||||
pageMoveForm.submit();
|
|
||||||
}
|
|
||||||
|
|
||||||
//초기화
|
|
||||||
fn_init();
|
|
||||||
@@ -0,0 +1,117 @@
|
|||||||
|
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 {
|
||||||
|
// Base64 디코딩
|
||||||
|
const decoded = decodeURIComponent(escape(atob(review.content)));
|
||||||
|
const delta = JSON.parse(decoded);
|
||||||
|
|
||||||
|
// Quill read-only 모드로 렌더링
|
||||||
|
contentDiv.innerHTML = ''; // 로딩 메시지 제거
|
||||||
|
this.quill = new Quill(contentDiv, {
|
||||||
|
readOnly: true,
|
||||||
|
modules: { toolbar: false },
|
||||||
|
theme: 'snow'
|
||||||
|
});
|
||||||
|
this.quill.setContents(delta);
|
||||||
|
|
||||||
|
// 툴바 숨기기 (snow 테마 기본 요소)
|
||||||
|
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) {
|
||||||
|
// Delta 파싱 실패 시 HTML로 시도
|
||||||
|
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,259 @@
|
|||||||
|
class ReviewListManager {
|
||||||
|
constructor() {
|
||||||
|
this.reviews = [];
|
||||||
|
this.currentPage = 1;
|
||||||
|
this.pageSize = 9;
|
||||||
|
this.totalCount = 0;
|
||||||
|
this.categoryDivCd = '07'; // 다이어트센터
|
||||||
|
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('조회 중 오류가 발생하였습니다.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Delta JSON에서 이미지 URL 배열 추출 */
|
||||||
|
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 [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Delta JSON에서 텍스트 요약 추출 */
|
||||||
|
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 ''; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 이미지 슬라이더 HTML 생성 */
|
||||||
|
buildSliderHtml(images, cardIdx) {
|
||||||
|
if (images.length === 0) {
|
||||||
|
return '<div class="review-no-image">📷</div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
const sliderId = `slider-${cardIdx}`;
|
||||||
|
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-slider-id="${sliderId}" 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;
|
||||||
|
const id = card.dataset.id;
|
||||||
|
location.href = `/webreview/selectProcedureReviewIntro.do?muProcedureReviewId=${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();
|
||||||
|
const dir = parseInt(arrow.dataset.dir);
|
||||||
|
let next = parseInt(slider.dataset.current) + 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();
|
||||||
145
src/main/resources/static/sitemap.xml
Normal file
@@ -0,0 +1,145 @@
|
|||||||
|
<?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://diet.madeu.co.kr/</loc>
|
||||||
|
<lastmod>2026-01-19T10:03:43+00:00</lastmod>
|
||||||
|
<priority>1.00</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://diet.madeu.co.kr/index</loc>
|
||||||
|
<lastmod>2026-01-19T10:03:43+00:00</lastmod>
|
||||||
|
<priority>0.80</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://diet.madeu.co.kr/webintroduction/selectIntroductionHospitalIntro.do</loc>
|
||||||
|
<lastmod>2026-01-19T10:03:43+00:00</lastmod>
|
||||||
|
<priority>0.80</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://diet.madeu.co.kr/webintroduction/selectIntroductionStaffIntro.do</loc>
|
||||||
|
<lastmod>2026-01-19T10:03:43+00:00</lastmod>
|
||||||
|
<priority>0.80</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://diet.madeu.co.kr/webintroduction/selectIntroductionWayIntro.do</loc>
|
||||||
|
<lastmod>2026-01-19T10:03:43+00:00</lastmod>
|
||||||
|
<priority>0.80</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://diet.madeu.co.kr/webservice/selectServiceIntro.do?categoryNo=1</loc>
|
||||||
|
<lastmod>2026-01-19T10:03:43+00:00</lastmod>
|
||||||
|
<priority>0.80</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://diet.madeu.co.kr/webservice/selectServiceDetailIntro.do?categoryDivCd=01&categoryNo=1&postNo=1</loc>
|
||||||
|
<lastmod>2026-01-19T10:03:43+00:00</lastmod>
|
||||||
|
<priority>0.80</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://diet.madeu.co.kr/webservice/selectServiceIntro.do?categoryNo=8</loc>
|
||||||
|
<lastmod>2026-01-19T10:03:43+00:00</lastmod>
|
||||||
|
<priority>0.80</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://diet.madeu.co.kr/webservice/selectServiceDetailIntro.do?categoryDivCd=01&categoryNo=8&postNo=3</loc>
|
||||||
|
<lastmod>2026-01-19T10:03:43+00:00</lastmod>
|
||||||
|
<priority>0.80</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://diet.madeu.co.kr/webservice/selectServiceDetailIntro.do?categoryDivCd=01&categoryNo=8&postNo=2</loc>
|
||||||
|
<lastmod>2026-01-19T10:03:43+00:00</lastmod>
|
||||||
|
<priority>0.80</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://diet.madeu.co.kr/webservice/selectServiceIntro.do?categoryNo=2</loc>
|
||||||
|
<lastmod>2026-01-19T10:03:43+00:00</lastmod>
|
||||||
|
<priority>0.80</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://diet.madeu.co.kr/webservice/selectServiceDetailIntro.do?categoryDivCd=01&categoryNo=2&postNo=1</loc>
|
||||||
|
<lastmod>2026-01-19T10:03:43+00:00</lastmod>
|
||||||
|
<priority>0.80</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://diet.madeu.co.kr/webservice/selectServiceDetailIntro.do?categoryDivCd=01&categoryNo=2&postNo=2</loc>
|
||||||
|
<lastmod>2026-01-19T10:03:43+00:00</lastmod>
|
||||||
|
<priority>0.80</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://diet.madeu.co.kr/webservice/selectServiceIntro.do?categoryNo=6</loc>
|
||||||
|
<lastmod>2026-01-19T10:03:43+00:00</lastmod>
|
||||||
|
<priority>0.80</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://diet.madeu.co.kr/webservice/selectServiceDetailIntro.do?categoryDivCd=01&categoryNo=6&postNo=1</loc>
|
||||||
|
<lastmod>2026-01-19T10:03:43+00:00</lastmod>
|
||||||
|
<priority>0.80</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://diet.madeu.co.kr/webservice/selectServiceDetailIntro.do?categoryDivCd=01&categoryNo=6&postNo=2</loc>
|
||||||
|
<lastmod>2026-01-19T10:03:43+00:00</lastmod>
|
||||||
|
<priority>0.80</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://diet.madeu.co.kr/webservice/selectServiceIntro.do?categoryNo=3</loc>
|
||||||
|
<lastmod>2026-01-19T10:03:43+00:00</lastmod>
|
||||||
|
<priority>0.80</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://diet.madeu.co.kr/webservice/selectServiceDetailIntro.do?categoryDivCd=01&categoryNo=3&postNo=2</loc>
|
||||||
|
<lastmod>2026-01-19T10:03:43+00:00</lastmod>
|
||||||
|
<priority>0.80</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://diet.madeu.co.kr/webservice/selectServiceDetailIntro.do?categoryDivCd=01&categoryNo=3&postNo=1</loc>
|
||||||
|
<lastmod>2026-01-19T10:03:43+00:00</lastmod>
|
||||||
|
<priority>0.80</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://diet.madeu.co.kr/webservice/selectServiceDetailIntro.do?categoryDivCd=01&categoryNo=3&postNo=6</loc>
|
||||||
|
<lastmod>2026-01-19T10:03:43+00:00</lastmod>
|
||||||
|
<priority>0.80</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://diet.madeu.co.kr/webservice/selectServiceDetailIntro.do?categoryDivCd=01&categoryNo=3&postNo=7</loc>
|
||||||
|
<lastmod>2026-01-19T10:03:43+00:00</lastmod>
|
||||||
|
<priority>0.80</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://diet.madeu.co.kr/webservice/selectServiceDetailIntro.do?categoryDivCd=01&categoryNo=3&postNo=8</loc>
|
||||||
|
<lastmod>2026-01-19T10:03:43+00:00</lastmod>
|
||||||
|
<priority>0.80</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://diet.madeu.co.kr/webservice/selectServiceIntro.do?categoryNo=5</loc>
|
||||||
|
<lastmod>2026-01-19T10:03:43+00:00</lastmod>
|
||||||
|
<priority>0.80</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://diet.madeu.co.kr/webservice/selectServiceDetailIntro.do?categoryDivCd=01&categoryNo=5&postNo=1</loc>
|
||||||
|
<lastmod>2026-01-19T10:03:43+00:00</lastmod>
|
||||||
|
<priority>0.80</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://diet.madeu.co.kr/webevent/selectListWebEventIntro.do</loc>
|
||||||
|
<lastmod>2026-01-19T10:03:43+00:00</lastmod>
|
||||||
|
<priority>0.80</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://diet.madeu.co.kr/webphoto/selectListWebPhotoIntro.do</loc>
|
||||||
|
<lastmod>2026-01-19T10:03:43+00:00</lastmod>
|
||||||
|
<priority>0.80</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://diet.madeu.co.kr/webaccept/acceptSite.do</loc>
|
||||||
|
<lastmod>2026-01-19T10:03:43+00:00</lastmod>
|
||||||
|
<priority>0.80</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://diet.madeu.co.kr/webaccept/acceptPrivacy.do</loc>
|
||||||
|
<lastmod>2026-01-19T10:03:43+00:00</lastmod>
|
||||||
|
<priority>0.80</priority>
|
||||||
|
</url>
|
||||||
|
</urlset>
|
||||||
@@ -1,125 +1,135 @@
|
|||||||
<!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">
|
||||||
</th:block>
|
</th:block>
|
||||||
<th:block layout:fragment="layoutContent">
|
<th:block layout:fragment="layoutContent">
|
||||||
<div class="popup-background-mask"></div>
|
<div class="popup-background-mask"></div>
|
||||||
<main>
|
<main>
|
||||||
<section class="banner main_banner">
|
<section class="banner main_banner">
|
||||||
<div class="swiper main_banner_swiper">
|
<div class="swiper main_banner_swiper">
|
||||||
<div class="swiper-wrapper" id="mainBannerList">
|
<div class="swiper-wrapper" id="mainBannerList">
|
||||||
</div>
|
</div>
|
||||||
<div class="swiper-pagination main_banner_pagination"></div>
|
<div class="swiper-pagination main_banner_pagination"></div>
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
<section class="cont content1">
|
|
||||||
<div class="swiper-area">
|
|
||||||
<h3>
|
|
||||||
<span style="color:#fff;">MADE U</span> <span style="color:#ffcccc">시그니처</span>
|
|
||||||
</h3>
|
|
||||||
<div class="swiper cont1_swiper">
|
|
||||||
<div class="swiper-wrapper">
|
|
||||||
<div class="swiper-slide">
|
|
||||||
<img class="pc" src="/image/main-slide/signature_diet_medicine_20251001.jpg" alt="img">
|
|
||||||
<img class="mb" src="/image/main-slide/signature_diet_medicine_20251001.jpg" alt="img">
|
|
||||||
</div>
|
|
||||||
<div class="swiper-slide">
|
|
||||||
<img class="pc" src="/image/main-slide/지방분해주사_20250911.jpg" alt="img">
|
|
||||||
<img class="mb" src="/image/main-slide/지방분해주사_20250911.jpg" alt="img">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="swiper-pagination cont1_swiper_pagination"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
<section class="banner sub_banner">
|
|
||||||
<div class="swiper sub_banner_swiper">
|
|
||||||
<div class="swiper-wrapper" id="subBannerList">
|
|
||||||
<div class="swiper-slide" style="background:#666;">
|
|
||||||
<button class="detail_btn">Detail view ></button>
|
|
||||||
</div>
|
|
||||||
<div class="swiper-slide" style="background:#999;">
|
|
||||||
<button class="detail_btn">Detail view ></button>
|
|
||||||
</div>
|
|
||||||
<div class="swiper-slide" style="background:#ddd;">
|
|
||||||
<button class="detail_btn">Detail view ></button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="swiper-pagination sub_banner_pagination"></div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
<section class="cont content2">
|
|
||||||
<div class="swiper-area">
|
|
||||||
<h3>
|
|
||||||
<span style="color:#cc3333">MADE U</span> <span style="color:#000">프리미엄장비</span>
|
|
||||||
</h3>
|
|
||||||
<div class="swiper cont2_swiper">
|
|
||||||
<div class="swiper-wrapper">
|
|
||||||
<div class="swiper-slide">
|
|
||||||
<img class="pc" src="/image/main-slide/울핏_20250911.jpg" alt="img">
|
|
||||||
<img class="mb" src="/image/main-slide/울핏_20250911.jpg" alt="img">
|
|
||||||
</div>
|
|
||||||
<div class="swiper-slide">
|
|
||||||
<img class="pc" src="/image/main-slide/튠바디_20250911.jpg" alt="img">
|
|
||||||
<img class="mb" src="/image/main-slide/튠바디_20250911.jpg" alt="img">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="swiper-pagination cont2_swiper_pagination"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
<section class="instagram">
|
|
||||||
<div class="swiper-area">
|
|
||||||
<div class="instagram_top">
|
|
||||||
<h3>
|
|
||||||
MADE U 인스타그램<br/>
|
|
||||||
<span>@madeu_diet</span>
|
|
||||||
</h3>
|
|
||||||
<button class="more_btn" onClick="window.open('https://instagram.com/madeu_diet')">View more ≫</button>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="instagram_btm" id="instagramFeed">
|
</section>
|
||||||
<div class="swiper instagram_swiper">
|
<section class="cont content1">
|
||||||
<div class="swiper-wrapper" id="instagramList">
|
<div class="swiper-area">
|
||||||
</div>
|
<h3>
|
||||||
</div>
|
<span style="color:#fff;">MADE U</span> <span style="color:#ffcccc">시그니처</span>
|
||||||
<!-- 커스텀 내비게이션 하단 영역 -->
|
</h3>
|
||||||
<div class="instagram-swiper-footer">
|
<div class="swiper cont1_swiper">
|
||||||
<button class="custom-swiper-btn prev"></button>
|
<div class="swiper-wrapper">
|
||||||
<div class="custom-swiper-thumbs"></div>
|
<div class="swiper-slide">
|
||||||
<button class="custom-swiper-btn next"></button>
|
<img class="pc" src="/image/main-slide/signature_diet_medicine_20251001.jpg" alt="img">
|
||||||
</div>
|
<img class="mb" src="/image/main-slide/signature_diet_medicine_20251001.jpg" alt="img">
|
||||||
|
</div>
|
||||||
|
<div class="swiper-slide">
|
||||||
|
<img class="pc" src="/image/signature/20251024/쉬다주사.jpg" alt="img">
|
||||||
|
<img class="mb" src="/image/signature/20251024/쉬다주사.jpg" alt="img">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="swiper-pagination cont1_swiper_pagination"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="banner sub_banner">
|
||||||
|
<div class="swiper sub_banner_swiper">
|
||||||
|
<div class="swiper-wrapper" id="subBannerList">
|
||||||
|
<div class="swiper-slide" style="background:#666;">
|
||||||
|
<button class="detail_btn">Detail view ></button>
|
||||||
|
</div>
|
||||||
|
<div class="swiper-slide" style="background:#999;">
|
||||||
|
<button class="detail_btn">Detail view ></button>
|
||||||
|
</div>
|
||||||
|
<div class="swiper-slide" style="background:#ddd;">
|
||||||
|
<button class="detail_btn">Detail view ></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="swiper-pagination sub_banner_pagination"></div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="cont content2">
|
||||||
|
<div class="swiper-area">
|
||||||
|
<h3>
|
||||||
|
<span style="color:#cc3333">MADE U</span> <span style="color:#000">프리미엄장비</span>
|
||||||
|
</h3>
|
||||||
|
<div class="swiper cont2_swiper">
|
||||||
|
<div class="swiper-wrapper">
|
||||||
|
<div class="swiper-slide">
|
||||||
|
<img class="pc" src="/image/equip/20260313/온다리프팅(Body).jpg" alt="img">
|
||||||
|
<img class="mb" src="/image/equip/20260313/온다리프팅(Body).jpg" alt="img">
|
||||||
|
</div>
|
||||||
|
<div class="swiper-slide">
|
||||||
|
<img class="pc" src="/image/equip/20260313/튠바디.jpg" alt="img">
|
||||||
|
<img class="mb" src="/image/equip/20260313/튠바디.jpg" alt="img">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="swiper-slide">
|
||||||
|
<img class="pc" src="/image/equip/20260313/티타늄리프팅(Body).jpg" alt="img">
|
||||||
|
<img class="mb" src="/image/equip/20260313/티타늄리프팅(Body).jpg" alt="img">
|
||||||
|
</div>
|
||||||
|
<div class="swiper-slide">
|
||||||
|
<img class="pc" src="/image/equip/20260313/울핏.jpg" alt="img">
|
||||||
|
<img class="mb" src="/image/equip/20260313/울핏.jpg" alt="img">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="swiper-pagination cont2_swiper_pagination"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="instagram">
|
||||||
|
<div class="swiper-area">
|
||||||
|
<div class="instagram_top">
|
||||||
|
<h3>
|
||||||
|
MADE U 인스타그램<br />
|
||||||
|
<span>@madeu_diet</span>
|
||||||
|
</h3>
|
||||||
|
<button class="more_btn" onClick="window.open('https://instagram.com/madeu_diet')">View more
|
||||||
|
≫</button>
|
||||||
|
</div>
|
||||||
|
<div class="instagram_btm" id="instagramFeed">
|
||||||
|
<div class="swiper instagram_swiper">
|
||||||
|
<div class="swiper-wrapper" id="instagramList">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 커스텀 내비게이션 하단 영역 -->
|
||||||
|
<div class="instagram-swiper-footer">
|
||||||
|
<button class="custom-swiper-btn prev"></button>
|
||||||
|
<div class="custom-swiper-thumbs"></div>
|
||||||
|
<button class="custom-swiper-btn next"></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<!-- 팝업 -->
|
||||||
|
<div class="popup">
|
||||||
|
<div class="top">
|
||||||
|
<div class="tab-content" id="popupContentList"></div>
|
||||||
|
<ul class="nav nav-tabs" role="tablist" id="popupTabList"></ul>
|
||||||
|
</div>
|
||||||
|
<div class="btm">
|
||||||
|
<div class="left_box">
|
||||||
|
<input type="checkbox" id="today" />
|
||||||
|
<label for="today">오늘 하루 안보기</label>
|
||||||
|
</div>
|
||||||
|
<div class="right_box">
|
||||||
|
<button class="close_btn_btm" id="btnPopupClose"><img src="/image/web/close.png" alt="close" /></button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</div>
|
||||||
</main>
|
|
||||||
|
|
||||||
<!-- 팝업 -->
|
|
||||||
<div class="popup">
|
|
||||||
<div class="top">
|
|
||||||
<div class="tab-content" id="popupContentList"></div>
|
|
||||||
<ul class="nav nav-tabs" role="tablist" id="popupTabList"></ul>
|
|
||||||
</div>
|
|
||||||
<div class="btm">
|
|
||||||
<div class="left_box">
|
|
||||||
<input type="checkbox" id="today"/>
|
|
||||||
<label for="today">오늘 하루 안보기</label>
|
|
||||||
</div>
|
|
||||||
<div class="right_box">
|
|
||||||
<button class="close_btn_btm" id="btnPopupClose"><img src="/image/web/close.png" alt="close"/></button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</th:block>
|
</th:block>
|
||||||
<th:block layout:fragment="layoutContentScript">
|
<th:block layout:fragment="layoutContentScript">
|
||||||
<script>
|
<script>
|
||||||
// CDN_URL 전역 정의
|
// CDN_URL 전역 정의
|
||||||
const CDN_URL = "[(${@environment.getProperty('url.cdn')})]";
|
const CDN_URL = "[(${@environment.getProperty('url.cdn')})]";
|
||||||
</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>
|
||||||
@@ -10,16 +8,16 @@
|
|||||||
<main>
|
<main>
|
||||||
<section class="main_img">
|
<section class="main_img">
|
||||||
<div class="inner_wrap">
|
<div class="inner_wrap">
|
||||||
<img src="/image/web/introduction_main.png" alt="introduction"/>
|
<img src="/image/web/introduction_main.png" alt="introduction" />
|
||||||
<div class="text_box">
|
<div class="text_box">
|
||||||
<p class="hashtag">#맞춤진료 #만족스러운결과</p>
|
<p class="hashtag">#맞춤진료 #만족스러운결과</p>
|
||||||
<p class="title">
|
<p class="title">
|
||||||
<span>MADE U 강남본점</span><br/>
|
<span>MADE U 강남본점</span><br />
|
||||||
Total Beauty<br class="mb"/> One Stop System
|
Total Beauty<br class="mb" /> One Stop System
|
||||||
</p>
|
</p>
|
||||||
<p class="sub_text">
|
<p class="sub_text">
|
||||||
한 공간에서 고객 한분 한분께 자연스러운<br class="mb"/> 아름다움과 건강한 다이어트를 위해<br/>
|
한 공간에서 고객 한분 한분께 자연스러운<br class="mb" /> 아름다움과 건강한 다이어트를 위해<br />
|
||||||
항상 노력하는 함께하는<br class="mb"/> 조언자가 되어 드릴 것을 약속드립니다.
|
항상 노력하는 함께하는<br class="mb" /> 조언자가 되어 드릴 것을 약속드립니다.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -28,47 +26,47 @@
|
|||||||
<div class="inner_wrap">
|
<div class="inner_wrap">
|
||||||
<div class="text_box">
|
<div class="text_box">
|
||||||
<p class="hashtag">#차별화된 맞춤 플랜</p>
|
<p class="hashtag">#차별화된 맞춤 플랜</p>
|
||||||
<p class="title">Looking Around<br/>MADE <span class="red">U</span></p>
|
<p class="title">Looking Around<br />MADE <span class="red">U</span></p>
|
||||||
<p class="sub_title">
|
<p class="sub_title">
|
||||||
쾌적하고 안락한 공간을 제공하는<br/>
|
쾌적하고 안락한 공간을 제공하는<br />
|
||||||
<span>메이드유 강남본점</span>
|
<span>메이드유 강남본점</span>
|
||||||
</p>
|
</p>
|
||||||
<p class="sub_text">
|
<p class="sub_text">
|
||||||
깨끗한 공간, 친절한 상담을 제공<span class="pc">하겠습니다.</span>
|
깨끗한 공간, 친절한 상담을 제공<span class="pc">하겠습니다.</span>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<img src="/image/web/introduction_content1.png" alt="content1"/>
|
<img src="/image/web/introduction_content1.png" alt="content1" />
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<section class="content2">
|
<section class="content2">
|
||||||
<div class="inner_wrap">
|
<div class="inner_wrap">
|
||||||
<p class="mb">쉬운다이어트 방법 없을까?<br/><span>MADE U 시그니처 프로그램</span></p>
|
<p class="mb">쉬운다이어트 방법 없을까?<br /><span>MADE U 시그니처 프로그램</span></p>
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
<img src="/image/web/introduction_content2-1.png" alt="content2-1"/>
|
<img src="/image/web/introduction_content2-1.png" alt="content2-1" />
|
||||||
<div class="text_box">
|
<div class="text_box">
|
||||||
<p>One-On-One Customized Counseling</p>
|
<p>One-On-One Customized Counseling</p>
|
||||||
<p class="sub_title">
|
<p class="sub_title">
|
||||||
MADE U 강남본점만의<br/>
|
MADE U 강남본점만의<br />
|
||||||
<span>1:1 맞춤 상담</span>
|
<span>1:1 맞춤 상담</span>
|
||||||
</p>
|
</p>
|
||||||
<p class="sub_text">
|
<p class="sub_text">
|
||||||
고객님의 체형별 그리고 고민<br class="mb"/> 부위별 맞춤진료로,<br/>
|
고객님의 체형별 그리고 고민<br class="mb" /> 부위별 맞춤진료로,<br />
|
||||||
숨겨진 아름다움을 찾아드립니다.
|
숨겨진 아름다움을 찾아드립니다.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<img src="/image/web/introduction_content2-2.png" alt="content2-2"/>
|
<img src="/image/web/introduction_content2-2.png" alt="content2-2" />
|
||||||
<div class="text_box">
|
<div class="text_box">
|
||||||
<p>Trademark Application</p>
|
<p>Trademark Application</p>
|
||||||
<p class="sub_title">
|
<p class="sub_title">
|
||||||
MADE U 강남본점만의<br/>
|
MADE U 강남본점만의<br />
|
||||||
<span>특허<span class="red">✓</span>상표 출원</span>
|
<span>특허<span class="red">✓</span>상표 출원</span>
|
||||||
</p>
|
</p>
|
||||||
<p class="sub_text">
|
<p class="sub_text">
|
||||||
메이드유 강남본점에서 자체 개발한<br class="mb"/> 메쉬다 주사<br class="pc"/>
|
메이드유 강남본점에서 자체 개발한<br class="mb" /> 메쉬다 주사<br class="pc" />
|
||||||
레시피의 뛰어난<br class="mb"/> 효과를 바탕으로 다수의<br/>
|
레시피의 뛰어난<br class="mb" /> 효과를 바탕으로 다수의<br />
|
||||||
특허와 상표를 등록했습니다.
|
특허와 상표를 등록했습니다.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -77,151 +75,151 @@
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<section class="content3">
|
<section class="content3">
|
||||||
<div class="inner_wrap">
|
<div class="inner_wrap">
|
||||||
<p>국내 고가명품 최다보유<br><span>MADE U</span> 프리미엄 장비 소개</p>
|
<p>국내 고가명품 최다보유<br><span>MADE U</span> 프리미엄 장비 소개</p>
|
||||||
|
|
||||||
<div class="equipment-grid">
|
<div class="equipment-grid">
|
||||||
<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"><!-- 1,800,000<span>부터</span> --></p>
|
<p class="equipment-price"><!-- 1,800,000<span>부터</span> --></p>
|
||||||
</div>
|
</div>
|
||||||
</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"><!-- 400,000<span>부터</span> --></p>
|
<p class="equipment-price"><!-- 400,000<span>부터</span> --></p>
|
||||||
</div>
|
</div>
|
||||||
</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"><!-- 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-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">165,000<span>부터</span></p> -->
|
||||||
<p class="equipment-price"><!-- 150,000<span>부터</span> --></p>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="equipment-card">
|
||||||
|
<div class="equipment-image">
|
||||||
<!-- 2번째 행 -->
|
<img src="/image/equip/튠바디.jpg" alt="튠바디">
|
||||||
<div class="equipment-card">
|
</div>
|
||||||
<div class="equipment-image">
|
<div class="equipment-info">
|
||||||
<img src="/image/equip/튠페이스.jpg" alt="튠페이스">
|
<h3 class="equipment-name">튠바디</h3>
|
||||||
</div>
|
<!-- <p class="equipment-desc">깊은 탄력과 리프팅을 동시에</p> -->
|
||||||
<div class="equipment-info">
|
<p class="equipment-price"><!-- 150,000<span>부터</span> --></p>
|
||||||
<h3 class="equipment-name">튠페이스</h3>
|
</div>
|
||||||
<p class="equipment-desc">깊은 탄력과 리프팅을 동시에</p>
|
</div>
|
||||||
<p class="equipment-price"><!-- 400,000<span>부터</span> --></p>
|
|
||||||
</div>
|
<!-- 2번째 행 -->
|
||||||
</div>
|
<div class="equipment-card">
|
||||||
|
<div class="equipment-image">
|
||||||
<div class="equipment-card">
|
<img src="/image/equip/튠페이스.jpg" alt="튠페이스">
|
||||||
<div class="equipment-image">
|
</div>
|
||||||
<img src="/image/equip/울핏.jpg" alt="울핏">
|
<div class="equipment-info">
|
||||||
</div>
|
<h3 class="equipment-name">튠페이스</h3>
|
||||||
<div class="equipment-info">
|
<!-- <p class="equipment-desc">깊은 탄력과 리프팅을 동시에</p> -->
|
||||||
<h3 class="equipment-name">울핏</h3>
|
<p class="equipment-price"><!-- 400,000<span>부터</span> --></p>
|
||||||
<p class="equipment-desc">깊은 탄력과 리프팅을 동시에</p>
|
</div>
|
||||||
<p class="equipment-price"><!-- 50,000<span>부터</span> --></p>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
<div class="equipment-card">
|
||||||
|
<div class="equipment-image">
|
||||||
<div class="equipment-card">
|
<img src="/image/equip/울핏.jpg" alt="울핏">
|
||||||
<div class="equipment-image">
|
</div>
|
||||||
<img src="/image/equip/포텐자.jpg" alt="포텐자">
|
<div class="equipment-info">
|
||||||
</div>
|
<h3 class="equipment-name">울핏</h3>
|
||||||
<div class="equipment-info">
|
<!-- <p class="equipment-desc">깊은 탄력과 리프팅을 동시에</p> -->
|
||||||
<h3 class="equipment-name">포텐자</h3>
|
<p class="equipment-price"><!-- 50,000<span>부터</span> --></p>
|
||||||
<p class="equipment-desc">깊은 탄력과 리프팅을 동시에</p>
|
</div>
|
||||||
<p class="equipment-price"><!-- 150,000<span>부터</span> --></p>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
<div class="equipment-card">
|
||||||
|
<div class="equipment-image">
|
||||||
<div class="equipment-card">
|
<img src="/image/equip/포텐자.jpg" alt="포텐자">
|
||||||
<div class="equipment-image">
|
</div>
|
||||||
<img src="/image/equip/인모드.jpg" alt="인모드">
|
<div class="equipment-info">
|
||||||
</div>
|
<h3 class="equipment-name">포텐자</h3>
|
||||||
<div class="equipment-info">
|
<!-- <p class="equipment-desc">깊은 탄력과 리프팅을 동시에</p> -->
|
||||||
<h3 class="equipment-name">인모드</h3>
|
<p class="equipment-price"><!-- 150,000<span>부터</span> --></p>
|
||||||
<p class="equipment-desc">깊은 탄력과 리프팅을 동시에</p>
|
</div>
|
||||||
<p class="equipment-price"><!-- 100,000<span>부터</span> --></p>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
<div class="equipment-card">
|
||||||
|
<div class="equipment-image">
|
||||||
<!-- 3번째 행 -->
|
<img src="/image/equip/인모드.jpg" alt="인모드">
|
||||||
<div class="equipment-card">
|
</div>
|
||||||
<div class="equipment-image">
|
<div class="equipment-info">
|
||||||
<img src="/image/equip/슈링크유니버스.jpg" alt="슈링크유니버스">
|
<h3 class="equipment-name">인모드</h3>
|
||||||
</div>
|
<!-- <p class="equipment-desc">깊은 탄력과 리프팅을 동시에</p> -->
|
||||||
<div class="equipment-info">
|
<p class="equipment-price"><!-- 100,000<span>부터</span> --></p>
|
||||||
<h3 class="equipment-name">슈링크유니버스</h3>
|
</div>
|
||||||
<p class="equipment-desc">깊은 탄력과 리프팅을 동시에</p>
|
</div>
|
||||||
<p class="equipment-price"><!-- 89,000<span>부터</span> --></p>
|
|
||||||
</div>
|
<!-- 3번째 행 -->
|
||||||
</div>
|
<div class="equipment-card">
|
||||||
|
<div class="equipment-image">
|
||||||
<div class="equipment-card">
|
<img src="/image/equip/슈링크유니버스.jpg" alt="슈링크유니버스">
|
||||||
<div class="equipment-image">
|
</div>
|
||||||
<img src="/image/equip/바디고주파테라피.jpg" alt="바디고주파테라피">
|
<div class="equipment-info">
|
||||||
</div>
|
<h3 class="equipment-name">슈링크유니버스</h3>
|
||||||
<div class="equipment-info">
|
<!-- <p class="equipment-desc">깊은 탄력과 리프팅을 동시에</p> -->
|
||||||
<h3 class="equipment-name">바디고주파테라피</h3>
|
<p class="equipment-price"><!-- 89,000<span>부터</span> --></p>
|
||||||
<p class="equipment-desc">깊은 탄력과 리프팅을 동시에</p>
|
</div>
|
||||||
<p class="equipment-price"><!-- 100,000<span>부터</span> --></p>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
<div class="equipment-card">
|
||||||
|
<div class="equipment-image">
|
||||||
<div class="equipment-card">
|
<img src="/image/equip/바디고주파테라피.jpg" alt="바디고주파테라피">
|
||||||
<div class="equipment-image">
|
</div>
|
||||||
<img src="/image/equip/리포덤.jpg" alt="리포덤">
|
<div class="equipment-info">
|
||||||
</div>
|
<h3 class="equipment-name">바디고주파테라피</h3>
|
||||||
<div class="equipment-info">
|
<!-- <p class="equipment-desc">깊은 탄력과 리프팅을 동시에</p> -->
|
||||||
<h3 class="equipment-name">리포덤</h3>
|
<p class="equipment-price"><!-- 100,000<span>부터</span> --></p>
|
||||||
<p class="equipment-desc">깊은 탄력과 리프팅을 동시에</p>
|
</div>
|
||||||
<p class="equipment-price"><!-- 50,000<span>부터</span> --></p>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
<div class="equipment-card">
|
||||||
|
<div class="equipment-image">
|
||||||
<div class="equipment-card">
|
<img src="/image/equip/리포덤.jpg" alt="리포덤">
|
||||||
<div class="equipment-image">
|
</div>
|
||||||
<img src="/image/equip/라비앙.jpg" alt="라비앙">
|
<div class="equipment-info">
|
||||||
</div>
|
<h3 class="equipment-name">리포덤</h3>
|
||||||
<div class="equipment-info">
|
<!-- <p class="equipment-desc">깊은 탄력과 리프팅을 동시에</p> -->
|
||||||
<h3 class="equipment-name">라비앙</h3>
|
<p class="equipment-price"><!-- 50,000<span>부터</span> --></p>
|
||||||
<p class="equipment-desc">깊은 탄력과 리프팅을 동시에</p>
|
</div>
|
||||||
<p class="equipment-price"><!-- 165,000<span>부터</span> --></p>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="content4">
|
<section class="content4">
|
||||||
<div class="inner_wrap">
|
<div class="inner_wrap">
|
||||||
<p>
|
<p>
|
||||||
한 공간에서 고객 한분 한분께 자연스러운 아름다움과<br class="mb"/> 건강한 다이어트를 위해 항상 노력하는<br/>
|
한 공간에서 고객 한분 한분께 자연스러운 아름다움과<br class="mb" /> 건강한 다이어트를 위해 항상 노력하는<br />
|
||||||
<span>Total Beauty One Stop System</span>
|
<span>Total Beauty One Stop System</span>
|
||||||
</p>
|
</p>
|
||||||
<ul>
|
<ul>
|
||||||
@@ -229,56 +227,57 @@
|
|||||||
<div class="text_box">
|
<div class="text_box">
|
||||||
<p>
|
<p>
|
||||||
<span>
|
<span>
|
||||||
자연스러운 아름다움과<br/>
|
자연스러운 아름다움과<br />
|
||||||
건강한 다이어트
|
건강한 다이어트
|
||||||
</span>
|
</span>
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
메이드유는 <span>Total Beauty One Stop System</span>으로<br class="pc"/>
|
메이드유는 <span>Total Beauty One Stop System</span>으로<br class="pc" />
|
||||||
한 공간에서 고객 한분 <br class="mb"/>한분께 자연스러운 아름다움과<br/>
|
한 공간에서 고객 한분 <br class="mb" />한분께 자연스러운 아름다움과<br />
|
||||||
건강한 다이어트를 위해 항상 노력하는 함께하는 조언자가<br class="pc"/>
|
건강한 다이어트를 위해 항상 노력하는 함께하는 조언자가<br class="pc" />
|
||||||
되어 드릴 것을 약속드립니다.
|
되어 드릴 것을 약속드립니다.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<img class="pc" src="/image/web/introduction_content4-1.jpg" alt="introduction_content4-1"/>
|
<img class="pc" src="/image/web/introduction_content4-1.jpg" alt="introduction_content4-1" />
|
||||||
<img class="mb" src="/image/web/Mintroduction_content4-1.jpg" alt="introduction_content4-1"/>
|
<img class="mb" src="/image/web/Mintroduction_content4-1.jpg" alt="introduction_content4-1" />
|
||||||
</li>
|
</li>
|
||||||
<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" />만족할 수 있는
|
||||||
더 나은 감동을 선사하기 위해<br/>
|
결과,</span><br />
|
||||||
|
더 나은 감동을 선사하기 위해<br />
|
||||||
끊임없이 노력하겠습니다.
|
끊임없이 노력하겠습니다.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
메이드유는 <span>전국, 해외에서 찾아오는 비만센터와<br class="pc"/> 프리미멈 명품
|
메이드유는 <span>전국, 해외에서 찾아오는 비만센터와<br class="pc" /> 프리미멈 명품
|
||||||
장비 보유 및 장비 최다 보유</span>와 엘란쎄, <br class="pc"/>스컬트라 콜라겐 볼륨
|
장비 보유 및 장비 최다 보유</span>와 엘란쎄, <br class="pc" />스컬트라 콜라겐 볼륨
|
||||||
전국 3대 병원인 쁘띠 센터로 <br class="pc"/>구분되어 고객에 맞춰 운영되고
|
전국 3대 병원인 쁘띠 센터로 <br class="pc" />구분되어 고객에 맞춰 운영되고
|
||||||
있습니다.
|
있습니다.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<img class="pc" src="/image/web/introduction_content4-2.jpg" alt="introduction_content4-2"/>
|
<img class="pc" src="/image/web/introduction_content4-2.jpg" alt="introduction_content4-2" />
|
||||||
<img class="mb" src="/image/web/Mintroduction_content4-2.jpg" alt="introduction_content4-2"/>
|
<img class="mb" src="/image/web/Mintroduction_content4-2.jpg" alt="introduction_content4-2" />
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<div class="text_box">
|
<div class="text_box">
|
||||||
<p>
|
<p>
|
||||||
No Pain 통증 없이<br/>
|
No Pain 통증 없이<br />
|
||||||
No Bruise 멍 없이<br/>
|
No Bruise 멍 없이<br />
|
||||||
No Swelling 붓기 없이<br/>
|
No Swelling 붓기 없이<br />
|
||||||
<span>3No 의료서비스를 지향</span>
|
<span>3No 의료서비스를 지향</span>
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
모든 제품은 정품, 정량, 정품 장비 사용을 원칙으로 안전을 <br class="pc"/>
|
모든 제품은 정품, 정량, 정품 장비 사용을 원칙으로 안전을 <br class="pc" />
|
||||||
최우선으로 하고 있으며, 모든 시술은 <span>No Pain, No Bruise, <br class="pc"/>
|
최우선으로 하고 있으며, 모든 시술은 <span>No Pain, No Bruise, <br class="pc" />
|
||||||
No Swelling라는 3No 의료서비스를 지향</span>합니다. <br class="pc"/>
|
No Swelling라는 3No 의료서비스를 지향</span>합니다. <br class="pc" />
|
||||||
앞으로도 고품질의 관리와 서비스를 받을 수 있도록 노력하며 <br class="pc"/>
|
앞으로도 고품질의 관리와 서비스를 받을 수 있도록 노력하며 <br class="pc" />
|
||||||
사소한 불편까지 읽어주는 세심한 배려, 마음까지 읽는 서비스로<br class="pc"/>
|
사소한 불편까지 읽어주는 세심한 배려, 마음까지 읽는 서비스로<br class="pc" />
|
||||||
무한 감동을 드릴 것을 약속합니다.
|
무한 감동을 드릴 것을 약속합니다.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<img class="pc" src="/image/web/introduction_content4-3.jpg" alt="introduction_content4-3"/>
|
<img class="pc" src="/image/web/introduction_content4-3.jpg" alt="introduction_content4-3" />
|
||||||
<img class="mb" src="/image/web/Mintroduction_content4-3.jpg" alt="introduction_content4-3"/>
|
<img class="mb" src="/image/web/Mintroduction_content4-3.jpg" alt="introduction_content4-3" />
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
@@ -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" />
|
||||||
@@ -15,17 +14,15 @@
|
|||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE10">
|
<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE10">
|
||||||
|
|
||||||
<!-- sns미리보기 -->
|
|
||||||
<meta property="og:type" content="website">
|
|
||||||
<!-- <meta property="og:url" content="https://ntsoft.kr/"> -->
|
|
||||||
<meta property="og:image" content="">
|
|
||||||
<meta property="og:title" content="메이드유">
|
|
||||||
<meta property="og:description" content="설명문구">
|
|
||||||
|
|
||||||
<!-- 사이트등록및소유확인 -->
|
<!-- 사이트등록및소유확인 -->
|
||||||
<meta name="naver-site-verification" content="" />
|
<meta name="naver-site-verification" content="194ca1bb5bf1c69ced9c4c9693bef1adacb4acd4" />
|
||||||
|
|
||||||
<title>메이드유</title>
|
<meta name="description" content="강남 다이어트 전문 메이드유 강남본점, 1:1 맞춤 프로그램으로 건강한 체중감량과 요요 관리까지 체계적으로 진행합니다.고민을 정교하게 해결해드립니다.">
|
||||||
|
<meta property="og:type" content="website">
|
||||||
|
<meta property="og:title" content="메이드유 강남본점ㅣ강남다이어트병원">
|
||||||
|
<meta name="og:description" content="강남 다이어트 전문 메이드유 강남본점, 1:1 맞춤 프로그램으로 건강한 체중감량과 요요 관리까지 체계적으로 진행합니다.고민을 정교하게 해결해드립니다.">
|
||||||
|
|
||||||
|
<title>메이드유 강남본점ㅣ강남다이어트병원</title>
|
||||||
|
|
||||||
<!-- 파비콘 -->
|
<!-- 파비콘 -->
|
||||||
<link rel="shortcut icon" href="" type="image/x-icon">
|
<link rel="shortcut icon" href="" type="image/x-icon">
|
||||||
|
|||||||
@@ -1,99 +1,114 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
|
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
|
||||||
<th:block th:fragment="layoutHeader">
|
<th:block th:fragment="layoutHeader">
|
||||||
<th:block th:replace="/web/layout/layoutModal :: layoutModal"></th:block>
|
<th:block th:replace="/web/layout/layoutModal :: layoutModal"></th:block>
|
||||||
<link rel="stylesheet" href="/css/web/quick_menu/quick_menu.css">
|
<link rel="stylesheet" href="/css/web/quick_menu/quick_menu.css">
|
||||||
<script>
|
<script>
|
||||||
// 디바이스 감지 함수
|
// 디바이스 감지 함수
|
||||||
function isMobileDevice() {
|
function isMobileDevice() {
|
||||||
return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)
|
return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)
|
||||||
|| window.innerWidth <= 768;
|
|| window.innerWidth <= 768;
|
||||||
}
|
}
|
||||||
function movePetitCenter(){
|
function movePetitCenter() {
|
||||||
window.location.href="https://petit.madeu.co.kr/index";
|
window.location.href = "https://petit.madeu.co.kr/index";
|
||||||
}
|
}
|
||||||
// 카카오톡 상담 함수 (모든 디바이스에서 동작)
|
// 카카오톡 상담 함수 (모든 디바이스에서 동작)
|
||||||
function openKakaoTalk() {
|
function openKakaoTalk() {
|
||||||
window.open('https://pf.kakao.com/_puZExd', '_blank');
|
window.open('https://pf.kakao.com/_puZExd', '_blank');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 전화걸기 함수 (모바일에서만 동작)
|
|
||||||
function makePhoneCall() {
|
|
||||||
if (isMobileDevice()) {
|
|
||||||
// 모바일에서만 전화걸기
|
|
||||||
window.location.href = 'tel:02-547-4711';
|
|
||||||
} else {
|
|
||||||
// 데스크톱에서는 동작 안함 (필요시 알림 추가)
|
|
||||||
console.log('전화걸기는 모바일에서만 가능합니다.');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 모바일 여부 확인 함수
|
|
||||||
function isMobile() {
|
|
||||||
return window.innerWidth <= 768; // 필요 시 기준 너비 조정
|
|
||||||
}
|
|
||||||
|
|
||||||
// 현재 경로가 /index인지 확인
|
function moveEvent() {
|
||||||
function isIndexPage() {
|
window.location.href = "https://diet.madeu.co.kr/webevent/selectListWebEventIntro.do";
|
||||||
return window.location.pathname === '/index'; // '/index.html'인 경우 조정 필요
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// 퀵메뉴 표시/숨김 함수
|
function moveReview() {
|
||||||
function toggleQuickMenu() {
|
window.location.href = "https://diet.madeu.co.kr/webreview/selectListProcedureReviewIntro.do";
|
||||||
const quickMenu = document.querySelector('.quick-menu-simple');
|
}
|
||||||
if (!quickMenu) return; // 요소가 없으면 종료
|
|
||||||
|
|
||||||
if (isMobile()) {
|
// 전화걸기 함수 (모바일에서만 동작)
|
||||||
// 모바일: /index일 때만 표시
|
function makePhoneCall() {
|
||||||
quickMenu.style.display = isIndexPage() ? '' : 'none';
|
if (isMobileDevice()) {
|
||||||
} else {
|
// 모바일에서만 전화걸기
|
||||||
// 데스크톱: 항상 표시
|
window.location.href = 'tel:02-547-4711';
|
||||||
quickMenu.style.display = '';
|
} else {
|
||||||
}
|
// 데스크톱에서는 동작 안함 (필요시 알림 추가)
|
||||||
}
|
console.log('전화걸기는 모바일에서만 가능합니다.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 모바일 여부 확인 함수
|
||||||
|
function isMobile() {
|
||||||
|
return window.innerWidth <= 768; // 필요 시 기준 너비 조정
|
||||||
|
}
|
||||||
|
|
||||||
// 페이지 로드와 리사이즈 이벤트 연결
|
// 현재 경로가 /index인지 확인
|
||||||
window.addEventListener('load', toggleQuickMenu);
|
function isIndexPage() {
|
||||||
window.addEventListener('resize', toggleQuickMenu);
|
return window.location.pathname === '/index'; // '/index.html'인 경우 조정 필요
|
||||||
</script>
|
}
|
||||||
<header>
|
|
||||||
<div class="inner_wrap">
|
// 퀵메뉴 표시/숨김 함수
|
||||||
<button class="mb mbmenu" onClick="openNav()"></button>
|
function toggleQuickMenu() {
|
||||||
<a class="logo" href="/index"><img src="/image/logo_199x54.png" alt="logo"></a>
|
const quickMenu = document.querySelector('.quick-menu-simple');
|
||||||
<nav>
|
if (!quickMenu) return; // 요소가 없으면 종료
|
||||||
<ul class="depth1">
|
|
||||||
<li th:each="menu : ${menuList}">
|
if (isMobile()) {
|
||||||
<a class="mmenu" th:href="${menu.menuUrl}" th:text="${menu.menuName}"></a>
|
// 모바일: /index일 때만 표시
|
||||||
<ul class="depth2" th:if="${#lists.size(menu.children) > 0}">
|
quickMenu.style.display = isIndexPage() ? '' : 'none';
|
||||||
<li></li>
|
} else {
|
||||||
<li th:each="subMenu : ${menu.children}">
|
// 데스크톱: 항상 표시
|
||||||
<a th:href="${subMenu.menuUrl}" th:text="${subMenu.menuName}"></a>
|
quickMenu.style.display = '';
|
||||||
</li>
|
}
|
||||||
</ul>
|
}
|
||||||
</li>
|
|
||||||
</ul>
|
// 페이지 로드와 리사이즈 이벤트 연결
|
||||||
</nav>
|
window.addEventListener('load', toggleQuickMenu);
|
||||||
|
window.addEventListener('resize', toggleQuickMenu);
|
||||||
|
</script>
|
||||||
|
<header>
|
||||||
|
<div class="inner_wrap">
|
||||||
|
<button class="mb mbmenu" onClick="openNav()"></button>
|
||||||
|
<a class="logo" href="/index"><img src="/image/logo_199x54.png" alt="logo"></a>
|
||||||
|
<nav>
|
||||||
|
<ul class="depth1">
|
||||||
|
<li th:each="menu : ${menuList}">
|
||||||
|
<a class="mmenu" th:href="${menu.menuUrl}" th:text="${menu.menuName}"></a>
|
||||||
|
<ul class="depth2" th:if="${#lists.size(menu.children) > 0}">
|
||||||
|
<li></li>
|
||||||
|
<li th:each="subMenu : ${menu.children}">
|
||||||
|
<a th:href="${subMenu.menuUrl}" th:text="${subMenu.menuName}"></a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<!-- 퀵메뉴 -->
|
||||||
|
<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="movePetitCenter()">
|
||||||
|
<img src="/image/quick_menu/petit_center.png" alt="쁘띠센터">
|
||||||
|
</div>
|
||||||
|
<!-- 카카오톡 상담 -->
|
||||||
|
<div class="quick-item kakao-consult" onclick="openKakaoTalk()">
|
||||||
|
<img src="/image/quick_menu/kakao_consultation.png" alt="카카오톡 상담">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 전화 상담 -->
|
||||||
|
<div class="quick-item phone-consult" onclick="makePhoneCall()">
|
||||||
|
<div class="phone-default">
|
||||||
|
<img src="/image/quick_menu/call_consultation.png" alt="전화 상담">
|
||||||
|
</div>
|
||||||
|
<div class="phone-number">
|
||||||
|
<img src="/image/quick_menu/madeu_phone_number.png" alt="전화 상담">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
<script src="/js/web/layout/layoutHeader.js?ver=1"></script>
|
||||||
<!-- 퀵메뉴 -->
|
|
||||||
<div class="quick-menu-simple">
|
|
||||||
<div class="quick-item" onclick="movePetitCenter()">
|
|
||||||
<img src="/image/quick_menu/petit_center.png" alt="쁘띠센터">
|
|
||||||
</div>
|
|
||||||
<!-- 카카오톡 상담 -->
|
|
||||||
<div class="quick-item kakao-consult" onclick="openKakaoTalk()">
|
|
||||||
<img src="/image/quick_menu/kakao_consultation.png" alt="카카오톡 상담">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 전화 상담 -->
|
|
||||||
<div class="quick-item phone-consult" onclick="makePhoneCall()">
|
|
||||||
<div class="phone-default">
|
|
||||||
<img src="/image/quick_menu/call_consultation.png" alt="전화 상담">
|
|
||||||
</div>
|
|
||||||
<div class="phone-number">
|
|
||||||
<img src="/image/quick_menu/madeu_phone_number.png" alt="전화 상담">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<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,432 +1,21 @@
|
|||||||
<!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">
|
||||||
<script th:inline="javascript">
|
<script th:inline="javascript">
|
||||||
let category_div_cd = [[${CATEGORY_DIV_CD}]];
|
let category_div_cd = [[${ CATEGORY_DIV_CD }]];
|
||||||
let category_no = [[${CATEGORY_NO}]];
|
let category_no = [[${ CATEGORY_NO }]];
|
||||||
let post_no = [[${POST_NO}]];
|
let post_no = [[${ POST_NO }]];
|
||||||
const CDN_URL = [[${@environment.getProperty('url.cdn')}]];
|
const CDN_URL = [[${@environment.getProperty('url.cdn') }]];
|
||||||
</script>
|
</script>
|
||||||
</th:block>
|
</th:block>
|
||||||
|
|
||||||
<th:block layout:fragment="layoutContent">
|
<th:block layout:fragment="layoutContent">
|
||||||
@@ -439,11 +28,11 @@ const CDN_URL = [[${@environment.getProperty('url.cdn')}]];
|
|||||||
<img id="serviceThumb" th:src="${@environment.getProperty('madeu.logo.size800x450')}" alt="썸네일 이미지">
|
<img id="serviceThumb" th:src="${@environment.getProperty('madeu.logo.size800x450')}" alt="썸네일 이미지">
|
||||||
<pre id="thumbnail-bottom-txt"></pre>
|
<pre id="thumbnail-bottom-txt"></pre>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="info-box">
|
<div class="info-box">
|
||||||
<div class="info-title" id="title">메쉬다 D/S</div>
|
<div class="info-title" id="title">메쉬다 D/S</div>
|
||||||
<div class="info-desc" id="contents">전신 라인 정리에 특화된 메쉬다 바디주사!</div>
|
<div class="info-desc" id="contents">전신 라인 정리에 특화된 메쉬다 바디주사!</div>
|
||||||
|
|
||||||
<div class="hashtag-section">
|
<div class="hashtag-section">
|
||||||
<div class="hashtag-container">
|
<div class="hashtag-container">
|
||||||
<div class="hashtag-list">
|
<div class="hashtag-list">
|
||||||
@@ -458,14 +47,16 @@ const CDN_URL = [[${@environment.getProperty('url.cdn')}]];
|
|||||||
</div>
|
</div>
|
||||||
</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">
|
||||||
<label for="procedure-select">시술 선택</label>
|
<label for="procedure-select">시술 선택</label>
|
||||||
<select id="procedure-select" multiple></select>
|
<select id="procedure-select" multiple></select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="total-row">
|
<div class="total-row">
|
||||||
<span class="total-label">총 금액</span>
|
<span class="total-label">총 금액</span>
|
||||||
<span class="total-price" id="total">0원</span>
|
<span class="total-price" id="total">0원</span>
|
||||||
@@ -473,7 +64,7 @@ const CDN_URL = [[${@environment.getProperty('url.cdn')}]];
|
|||||||
<button class="reserve-btn" id="reserve-btn" disabled>시술 예약하기</button>
|
<button class="reserve-btn" id="reserve-btn" disabled>시술 예약하기</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="desc-section">
|
<div class="desc-section">
|
||||||
<!-- <div class="desc-content">
|
<!-- <div class="desc-content">
|
||||||
<img id="contents_path" th:src="${@environment.getProperty('madeu.logo.size800x450')}" alt="컨텐츠 이미지" width="100%" />
|
<img id="contents_path" th:src="${@environment.getProperty('madeu.logo.size800x450')}" alt="컨텐츠 이미지" width="100%" />
|
||||||
</div> -->
|
</div> -->
|
||||||
@@ -482,301 +73,9 @@ const CDN_URL = [[${@environment.getProperty('url.cdn')}]];
|
|||||||
</th:block>
|
</th:block>
|
||||||
|
|
||||||
<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,594 +1,56 @@
|
|||||||
<!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">
|
||||||
<script th:inline="javascript">
|
<script th:inline="javascript">
|
||||||
const CDN_URL = [[${@environment.getProperty('url.cdn')}]];
|
const CDN_URL = [[${@environment.getProperty('url.cdn') }]];
|
||||||
</script>
|
</script>
|
||||||
</th:block>
|
</th:block>
|
||||||
|
|
||||||
<th:block layout:fragment="layoutContent">
|
<th:block layout:fragment="layoutContent">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<!-- 상단 헤더 영역 -->
|
<!-- 상단 헤더 영역 -->
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<h1 class="page-title">이벤트 안내</h1>
|
<h1 class="page-title">이벤트 안내</h1>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 하단 콘텐츠 영역 (사이드바 + 메인) -->
|
<!-- 하단 콘텐츠 영역 (사이드바 + 메인) -->
|
||||||
<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>
|
</aside>
|
||||||
</aside>
|
|
||||||
|
<!-- 메인 콘텐츠 -->
|
||||||
<!-- 메인 콘텐츠 -->
|
<main class="main-content">
|
||||||
<main class="main-content">
|
<div class="event-list">
|
||||||
<div class="event-list">
|
<div class="event-grid" id="event-grid">
|
||||||
<div class="event-grid" id="event-grid">
|
<!-- 이벤트 카드 JS로 렌더링 -->
|
||||||
<!-- 이벤트 카드 JS로 렌더링 -->
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</main>
|
||||||
</main>
|
</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>
|
</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,54 @@
|
|||||||
|
<!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>
|
||||||
|
|
||||||
|
<!-- Quill 에디터 본문 -->
|
||||||
|
<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,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 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>
|
||||||