Compare commits
30 Commits
6b22974979
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 5e53f19f2a | |||
| f73751497a | |||
| d590a3ad48 | |||
| 8e61cfa559 | |||
| e31ff954e3 | |||
| 761092c2d7 | |||
| 145e0df564 | |||
| f4545ce91a | |||
| 3df9096eec | |||
| b1a427b435 | |||
| 4a764b8295 | |||
| c0d026f896 | |||
| 84f062c681 | |||
| 7f4aa950be | |||
| 029c45a193 | |||
| 462d8a15de | |||
| bacd1fe401 | |||
| 37174437cf | |||
| a057cf425e | |||
|
|
512c4b2458 | ||
|
|
d4dc0cd46c | ||
|
|
32629ea3be | ||
|
|
0f61856d53 | ||
|
|
575471f28f | ||
|
|
07dfb40876 | ||
|
|
6076210bfb | ||
|
|
fc00a8edfc | ||
|
|
868ccf01b1 | ||
|
|
f6792f44d3 | ||
|
|
aecac1cade |
1
.wiki
Submodule
10
Walkthrough.md
Normal file
@@ -0,0 +1,10 @@
|
||||
# MadeU Petit Home - 프로젝트 Walkthrough
|
||||
|
||||
최근 개발 환경 및 시스템에 적용된 주요 변경 사항과 기능 구현 내역을 요약한 문서입니다.
|
||||
|
||||
## 1. 프로젝트 초기 구성
|
||||
- **저장소 클론 및 환경 설정**: Git 리포지토리(`madeu_petit_home`) 초기 클론 작업 및 프론트엔드/백엔드 기본 환경 설정을 수행했습니다.
|
||||
|
||||
## 2. 검색 엔진 최적화(SEO) 반영
|
||||
- **Sitemap 파일 구축**: 구글, 네이버 등 주요 검색 엔진의 크롤링 봇이 웹사이트 내부의 페이지들을 효과적으로 수집하고 노출할 수 있도록 프로젝트 내에 `sitemap.xml` 파일을 생성하여 라우팅 지도를 구축했습니다.
|
||||
- **Open Graph (OG) 태그 적용**: 다이어트 홈 페이지 프로젝트와 동일하게 소셜 미디어 링크 공유 시 올바른 썸네일과 문구가 제공되도록 메타 태그(`og` 속성) 생성을 지원했습니다.
|
||||
94
rules.md
Normal file
@@ -0,0 +1,94 @@
|
||||
# 프로젝트 코딩 가이드라인 (Java Backend)
|
||||
|
||||
AI 에디터(Agent)는 다음 규칙을 항상 준수하여 코드를 작성하고 수정해야 합니다.
|
||||
|
||||
## 0. 기본 소통 규칙 (Communication)
|
||||
- **언어**: 사용자에 대한 모든 답변과 코드 설명은 항상 **한글(Korean)**로만 작성해야 합니다.
|
||||
|
||||
## 1. 패키지 구성 (Package Structure)
|
||||
- **베이스 패키지**: `com.madeuhome`
|
||||
- **컨트롤러 (Controller)**: `ctrl`
|
||||
- **서비스 (Service)**: `svc`
|
||||
- **DTO (Data Transfer Object)**: `dto`
|
||||
- **매퍼 (Mapper)**: `mapper`
|
||||
- **공통 서비스**: `com.madeuhome.common.service` (LogHistoryService 등 시스템 공통 모듈)
|
||||
|
||||
## 2. 파일 명명 규칙 및 구성 (File Naming Conventions)
|
||||
- **컨트롤러 (Controller)**: `[도메인명]Controller.java` (예: `ABCDController.java`)
|
||||
- **서비스 (Service)**: `[도메인명]Service.java` (인터페이스와 구현체(impl)를 분리하지 않고 Service 클래스 파일 하나로만 구현, 예: `ABCDService.java`)
|
||||
- **DTO**: `[도메인명]DTO.java` (예: `ABCDDTO.java`)
|
||||
- **매퍼 (Mapper)**: `[도메인명]Mapper.java` (예: `ABCDMapper.java`)
|
||||
- **XML Mapper**: `[도메인명]SqlMap.xml` (namespace는 Mapper 인터페이스의 **FQCN**과 반드시 일치)
|
||||
|
||||
## 3. URL 및 메소드 명명 규칙 (RequestMapping & Method Naming)
|
||||
|
||||
### 1) RequestMapping (URL) 및 컨트롤러 메소드명
|
||||
- 페이지 이동하는 url : `moveXXXX.do`
|
||||
- 팝업 오픈하는 url : `openXXXX.do`
|
||||
- 조회 url : `getXXXX.do`
|
||||
- 저장 url : `putXXXX.do`
|
||||
- 수정 url : `modXXXX.do`
|
||||
- 삭제 url : `delXXXX.do`
|
||||
- **단, 컨트롤러 메소드명은 위 url에서 `.do`를 제외한 이름과 동일하게 명명합니다.**
|
||||
|
||||
### 2) 서비스 메소드명
|
||||
- 서비스 메소드명은 **컨트롤러 메소드명과 동일**하게 명명합니다.
|
||||
- 조회: `getXXXX` / 목록 조회: `getXXXXList`
|
||||
- 저장: `putXXXX`
|
||||
- 수정: `modXXXX`
|
||||
- 삭제: `delXXXX`
|
||||
|
||||
### 3) Mapper 인터페이스 메소드명
|
||||
- 단일조회 : `selectXXXX`
|
||||
- 리스트조회 : `selectListXXXX`
|
||||
- insert : `insertXXXX`
|
||||
- update : `updateXXXX`
|
||||
- delete : `deleteXXXX`
|
||||
|
||||
## 4. 데이터베이스 연동 정보 (DB Connection)
|
||||
- `application-local.yml`의 설정을 기반으로 한 공통 접속 정보입니다.
|
||||
- **Host**: 183.98.184.84
|
||||
- **Port**: 3306
|
||||
- **Database**: madeu
|
||||
- **User**: madeu
|
||||
- **Password**: apdlemdb12#$
|
||||
|
||||
## 5. 아키텍처 및 코딩 원칙 (Architecture & Coding Principles)
|
||||
|
||||
### 5-1. 컨트롤러 원칙 (Skinny Controller)
|
||||
- 컨트롤러에는 비즈니스 로직이나 예외처리 로직을 넣지 않고, **서비스 메서드를 호출하는 1줄로만 작성**합니다.
|
||||
- 컨트롤러 클래스는 `@Controller` 대신 **`@RestController`**를 사용하며, `@ResponseBody`는 생략합니다.
|
||||
- 데이터 입출력 메소드의 파라미터는 **단일 DTO 하나만 `@RequestBody`**로 받습니다.
|
||||
- 파일 업로드가 포함된 경우에만 `@ModelAttribute` + `@RequestParam MultipartFile`을 허용합니다.
|
||||
- 화면 이동(`move~`) 메소드는 **`ModelAndView`를 리턴**합니다. (`@RestController`에서 String 리턴 시 뷰 이름이 아닌 응답 바디로 해석되므로)
|
||||
- 화면 이동 메소드의 뷰 경로는 **컨트롤러에서 직접 명시**합니다. (서비스에 위임 금지)
|
||||
|
||||
### 5-2. 서비스 원칙 (Service Layer)
|
||||
- 에러 처리(try-catch), 응답 메시지(msgCode, msgDesc) 설정은 **서비스 계층에서 전담**합니다.
|
||||
- `HttpServletRequest`, `HttpSession`은 `@Autowired`로 직접 주입받아 사용합니다. (Spring이 Request-scope 프록시로 제공)
|
||||
- `session.getAttribute("loginMemberId")`를 통해 로그인 ID를 가져오고, DTO에 설정합니다.
|
||||
|
||||
### 5-3. DTO 원칙 (DTO Communication)
|
||||
- **HashMap 사용 금지**. 컨트롤러 ↔ 서비스 ↔ 매퍼 간 모든 데이터는 **DTO 객체만 사용**합니다.
|
||||
- DTO에는 `@Data` (Lombok)을 사용합니다.
|
||||
- DTO 필드 구성:
|
||||
- **DB 컬럼 매핑 필드**: `muProcedureReviewId`, `title`, `content` 등
|
||||
- **조회 결과 전용 필드**: `rowNum`, `writeDate`, `writeName` 등
|
||||
- **검색/UI 변수**: `startDate`, `endDate`, `start`, `limit`, `sort`, `dir` 등
|
||||
- **응답 매핑 변수**: `msgCode`, `msgDesc`, `success`, `totalCount`, `rows`(Object 타입), `tId`
|
||||
|
||||
### 5-4. Mapper 원칙 (MyBatis Mapper)
|
||||
- Mapper는 **`@Mapper` 어노테이션을 사용한 인터페이스**로 작성합니다. (`SqlSessionDaoSupport` 상속 금지)
|
||||
- XML Mapper의 `namespace`는 Mapper 인터페이스의 **FQCN(Fully Qualified Class Name)**과 일치시킵니다.
|
||||
- XML의 `resultType`은 `hashmap` 대신 **DTO FQCN**을 사용합니다.
|
||||
- 예외: 도메인 외부 테이블 조회(카테고리 등)는 `hashmap` 허용
|
||||
- XML alias는 **DTO 필드명(camelCase)**과 정확히 일치시킵니다.
|
||||
- 단건 조회는 `List` 대신 **DTO 단일 객체를 리턴**합니다.
|
||||
|
||||
## 6. 파일 업로드 규칙 (File Upload)
|
||||
- `MultipartFile.transferTo()` 사용 시 반드시 **절대경로를 명시**합니다:
|
||||
```java
|
||||
File dest = new File(outDir, savedName);
|
||||
file.transferTo(dest.toPath().toAbsolutePath());
|
||||
```
|
||||
- 상대경로 사용 시 Tomcat 임시 디렉토리 기준으로 해석되어 오류가 발생합니다.
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.madeuhome.common.ctrl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -24,12 +23,13 @@ public class MenuController {
|
||||
String requestURI = request.getRequestURI();
|
||||
|
||||
// 특정 URL 패턴에만 메뉴 추가
|
||||
if (requestURI.endsWith("Intro.do") || requestURI.startsWith("/index") ) {
|
||||
/*
|
||||
* if (requestURI.endsWith("Intro.do") || requestURI.startsWith("/index") ) {
|
||||
* return menuService.getMenuHierarchy("MAIN"); }
|
||||
*/
|
||||
|
||||
|
||||
return menuService.getMenuHierarchy("MAIN");
|
||||
}
|
||||
|
||||
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,209 @@
|
||||
package com.madeuhome.controller.web.reservation;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
import com.madeuhome.constants.Constants;
|
||||
import com.madeuhome.service.web.reservation.ReservationService;
|
||||
import com.madeuhome.util.HttpUtil;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.servlet.http.HttpSession;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* 예약 컨트롤러
|
||||
*/
|
||||
@Controller
|
||||
@Slf4j
|
||||
public class ReservationController {
|
||||
|
||||
@Autowired
|
||||
private ReservationService reservationService;
|
||||
|
||||
/**
|
||||
* 예약 페이지 이동
|
||||
*/
|
||||
@RequestMapping(value = "/webservice/selectMakeReservation.do")
|
||||
public String selectMakeReservation(HttpSession session, HttpServletRequest request, Model model) {
|
||||
log.debug("ReservationController selectMakeReservation START");
|
||||
HashMap<String, Object> paramMap = HttpUtil.getParameterMap(request);
|
||||
model.addAttribute("CATEGORY_DIV_CD", paramMap.get("CATEGORY_DIV_CD"));
|
||||
model.addAttribute("CATEGORY_NO", paramMap.get("CATEGORY_NO"));
|
||||
model.addAttribute("POST_NO", paramMap.get("POST_NO"));
|
||||
model.addAttribute("PROCEDURE_ID", paramMap.get("PROCEDURE_ID"));
|
||||
log.debug("ReservationController selectMakeReservation END");
|
||||
return "/web/service/makeReservation";
|
||||
}
|
||||
|
||||
/**
|
||||
* 예약 시술 정보 조회
|
||||
*/
|
||||
@RequestMapping(value = "/webservice/selectReservation.do")
|
||||
public ModelAndView selectReservation(HttpSession session, HttpServletRequest request,
|
||||
HttpServletResponse response) {
|
||||
log.debug("ReservationController selectReservation START");
|
||||
|
||||
HashMap<String, Object> paramMap = HttpUtil.getParameterMap(request);
|
||||
HashMap<String, Object> map = new HashMap<>();
|
||||
StringBuffer errorMsg = new StringBuffer();
|
||||
|
||||
try {
|
||||
map = reservationService.selectReservation(paramMap);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
errorMsg.append(e);
|
||||
return null;
|
||||
} finally {
|
||||
if (Constants.OK == map.get("msgCode")) {
|
||||
} else {
|
||||
if (null == map.get("msgCode") || ("").equals(map.get("msgCode"))) {
|
||||
map.put("msgCode", Constants.FAIL);
|
||||
}
|
||||
map.put("success", false);
|
||||
if (null == map.get("msgDesc") || ("").equals(map.get("msgDesc"))) {
|
||||
map.put("msgDesc", "정상적으로 수행되지 않았습니다. 관리자에게 문의하시기 바랍니다.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log.debug("ReservationController selectReservation END");
|
||||
return HttpUtil.makeHashToJsonModelAndView(map);
|
||||
}
|
||||
|
||||
/**
|
||||
* 병원 휴일 조회 (달력 표출용)
|
||||
*/
|
||||
@RequestMapping(value = "/webservice/selectHospitalHolidayList.do")
|
||||
public ModelAndView selectHospitalHolidayList(HttpSession session, HttpServletRequest request,
|
||||
HttpServletResponse response) {
|
||||
log.debug("ReservationController selectHospitalHolidayList START");
|
||||
|
||||
HashMap<String, Object> paramMap = HttpUtil.getParameterMap(request);
|
||||
HashMap<String, Object> map = new HashMap<>();
|
||||
|
||||
try {
|
||||
map = reservationService.selectHospitalHolidayList(paramMap);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
} finally {
|
||||
if (Constants.OK != map.get("msgCode")) {
|
||||
map.put("msgCode", Constants.FAIL);
|
||||
map.put("success", false);
|
||||
if (null == map.get("msgDesc") || ("").equals(map.get("msgDesc"))) {
|
||||
map.put("msgDesc", "정상적으로 수행되지 않았습니다. 관리자에게 문의하시기 바랍니다.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log.debug("ReservationController selectHospitalHolidayList END");
|
||||
return HttpUtil.makeHashToJsonModelAndView(map);
|
||||
}
|
||||
|
||||
/**
|
||||
* 특정 날짜 운영시간 조회
|
||||
*/
|
||||
@RequestMapping(value = "/webservice/selectHospitalWorkTime.do")
|
||||
public ModelAndView selectHospitalWorkTime(HttpSession session, HttpServletRequest request,
|
||||
HttpServletResponse response) {
|
||||
log.debug("ReservationController selectHospitalWorkTime START");
|
||||
|
||||
HashMap<String, Object> paramMap = HttpUtil.getParameterMap(request);
|
||||
HashMap<String, Object> map = new HashMap<>();
|
||||
|
||||
try {
|
||||
map = reservationService.selectHospitalWorkTime(paramMap);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
} finally {
|
||||
if (Constants.OK != map.get("msgCode")) {
|
||||
map.put("msgCode", Constants.FAIL);
|
||||
map.put("success", false);
|
||||
if (null == map.get("msgDesc") || ("").equals(map.get("msgDesc"))) {
|
||||
map.put("msgDesc", "정상적으로 수행되지 않았습니다. 관리자에게 문의하시기 바랍니다.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log.debug("ReservationController selectHospitalWorkTime END");
|
||||
return HttpUtil.makeHashToJsonModelAndView(map);
|
||||
}
|
||||
|
||||
/**
|
||||
* 예약 카운트 조회
|
||||
*/
|
||||
@RequestMapping(value = "/webservice/selectReservationCnt.do")
|
||||
public ModelAndView selectReservationCnt(HttpSession session, HttpServletRequest request,
|
||||
HttpServletResponse response) {
|
||||
log.debug("ReservationController selectReservationCnt START");
|
||||
|
||||
HashMap<String, Object> paramMap = HttpUtil.getParameterMap(request);
|
||||
HashMap<String, Object> map = new HashMap<>();
|
||||
StringBuffer errorMsg = new StringBuffer();
|
||||
|
||||
try {
|
||||
map = reservationService.selectReservationCnt(paramMap);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
errorMsg.append(e);
|
||||
return null;
|
||||
} finally {
|
||||
if (Constants.OK == map.get("msgCode")) {
|
||||
} else {
|
||||
if (null == map.get("msgCode") || ("").equals(map.get("msgCode"))) {
|
||||
map.put("msgCode", Constants.FAIL);
|
||||
}
|
||||
map.put("success", false);
|
||||
if (null == map.get("msgDesc") || ("").equals(map.get("msgDesc"))) {
|
||||
map.put("msgDesc", "정상적으로 수행되지 않았습니다. 관리자에게 문의하시기 바랍니다.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log.debug("ReservationController selectReservationCnt END");
|
||||
return HttpUtil.makeHashToJsonModelAndView(map);
|
||||
}
|
||||
|
||||
/**
|
||||
* 예약 저장
|
||||
*/
|
||||
@RequestMapping(value = "/webservice/insertReservation.do")
|
||||
public ModelAndView insertReservation(HttpSession session, HttpServletRequest request,
|
||||
HttpServletResponse response) {
|
||||
log.debug("ReservationController insertReservation START");
|
||||
|
||||
HashMap<String, Object> paramMap = HttpUtil.getParameterMap(request);
|
||||
HashMap<String, Object> map = new HashMap<>();
|
||||
StringBuffer errorMsg = new StringBuffer();
|
||||
|
||||
try {
|
||||
map = reservationService.insertReservation(paramMap);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
errorMsg.append(e);
|
||||
return null;
|
||||
} finally {
|
||||
if (Constants.OK == map.get("msgCode")) {
|
||||
} else {
|
||||
if (null == map.get("msgCode") || ("").equals(map.get("msgCode"))) {
|
||||
map.put("msgCode", Constants.FAIL);
|
||||
}
|
||||
map.put("success", false);
|
||||
if (null == map.get("msgDesc") || ("").equals(map.get("msgDesc"))) {
|
||||
map.put("msgDesc", "정상적으로 수행되지 않았습니다. 관리자에게 문의하시기 바랍니다.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log.debug("ReservationController insertReservation END");
|
||||
return HttpUtil.makeHashToJsonModelAndView(map);
|
||||
}
|
||||
}
|
||||
@@ -18,10 +18,9 @@ import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
|
||||
@Slf4j
|
||||
@Controller
|
||||
public class WebEventController extends ManagerDraftAction{
|
||||
public class WebEventController extends ManagerDraftAction {
|
||||
|
||||
@Autowired
|
||||
private WebEventService webEventService;
|
||||
@@ -36,8 +35,8 @@ public class WebEventController extends ManagerDraftAction{
|
||||
* @param response
|
||||
* @return
|
||||
*/
|
||||
@RequestMapping(value="/webevent/selectListWebEventIntro.do")
|
||||
public String selectListWebEventIntro(HttpSession session,HttpServletRequest request) {
|
||||
@RequestMapping(value = "/webevent/selectListWebEventIntro.do")
|
||||
public String selectListWebEventIntro(HttpSession session, HttpServletRequest request) {
|
||||
|
||||
log.debug("WebEventController selectListWebEventIntro START");
|
||||
|
||||
@@ -52,8 +51,9 @@ public class WebEventController extends ManagerDraftAction{
|
||||
* @param response
|
||||
* @return
|
||||
*/
|
||||
@RequestMapping(value="/webevent/selectListWebEvent.do")
|
||||
public ModelAndView selectListWebEvent(HttpSession session,HttpServletRequest request, HttpServletResponse response) {
|
||||
@RequestMapping(value = "/webevent/selectListWebEvent.do")
|
||||
public ModelAndView selectListWebEvent(HttpSession session, HttpServletRequest request,
|
||||
HttpServletResponse response) {
|
||||
|
||||
log.debug("WebEventController selectListWebEvent START");
|
||||
|
||||
@@ -61,24 +61,24 @@ public class WebEventController extends ManagerDraftAction{
|
||||
HashMap<String, Object> map = new HashMap<String, Object>();
|
||||
StringBuffer errorMsg = new StringBuffer();
|
||||
|
||||
try{
|
||||
try {
|
||||
map = webEventService.selectListWebEvent(paramMap);
|
||||
log.debug(map + "");
|
||||
}catch (Exception e) {
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
errorMsg.append(e);
|
||||
return null;
|
||||
}finally {
|
||||
if(Constants.OK == map.get("msgCode")) {
|
||||
} finally {
|
||||
if (Constants.OK == map.get("msgCode")) {
|
||||
|
||||
}else{
|
||||
if(null == map.get("msgCode") || ("").equals(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)");
|
||||
if (null == map.get("msgDesc") || ("").equals(map.get("msgDesc"))) {
|
||||
map.put("msgDesc", "정상적으로 수행되지 않았습니다. 관리자에게 문의하시기 바랍니다. (E0029)");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,16 +94,16 @@ public class WebEventController extends ManagerDraftAction{
|
||||
insertMap.put("requestValue", String.valueOf(paramMap));
|
||||
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");
|
||||
}else{
|
||||
} else {
|
||||
insertMap.put("resultCode", "ERROR");
|
||||
}
|
||||
|
||||
insertMap.put("resultMsg", String.valueOf(errorMsg));
|
||||
insertMap.put("muMemberId", paramMap.get("muMemberId"));
|
||||
|
||||
// logHistoryService.insertLogHistory(insertMap, visitLogParamMap);
|
||||
// logHistoryService.insertLogHistory(insertMap, visitLogParamMap);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
@@ -111,7 +111,6 @@ public class WebEventController extends ManagerDraftAction{
|
||||
|
||||
log.debug("WebEventController selectListWebEvent END");
|
||||
|
||||
|
||||
return HttpUtil.makeHashToJsonModelAndView(map);
|
||||
}
|
||||
|
||||
@@ -122,8 +121,8 @@ public class WebEventController extends ManagerDraftAction{
|
||||
* @param response
|
||||
* @return
|
||||
*/
|
||||
@RequestMapping(value="/webevent/selectListEvent.do")
|
||||
public ModelAndView selectListEvent(HttpSession session,HttpServletRequest request, HttpServletResponse response) {
|
||||
@RequestMapping(value = "/webevent/selectListEvent.do")
|
||||
public ModelAndView selectListEvent(HttpSession session, HttpServletRequest request, HttpServletResponse response) {
|
||||
|
||||
log.debug("WebEventController selectListEvent START");
|
||||
|
||||
@@ -131,24 +130,24 @@ public class WebEventController extends ManagerDraftAction{
|
||||
HashMap<String, Object> map = new HashMap<String, Object>();
|
||||
StringBuffer errorMsg = new StringBuffer();
|
||||
|
||||
try{
|
||||
try {
|
||||
map = webEventService.selectListEvent(paramMap);
|
||||
log.debug(map + "");
|
||||
}catch (Exception e) {
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
errorMsg.append(e);
|
||||
return null;
|
||||
}finally {
|
||||
if(Constants.OK == map.get("msgCode")) {
|
||||
} finally {
|
||||
if (Constants.OK == map.get("msgCode")) {
|
||||
|
||||
}else{
|
||||
if(null == map.get("msgCode") || ("").equals(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)");
|
||||
if (null == map.get("msgDesc") || ("").equals(map.get("msgDesc"))) {
|
||||
map.put("msgDesc", "정상적으로 수행되지 않았습니다. 관리자에게 문의하시기 바랍니다. (E0029)");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,15 +163,15 @@ public class WebEventController extends ManagerDraftAction{
|
||||
insertMap.put("requestValue", String.valueOf(paramMap));
|
||||
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");
|
||||
}else{
|
||||
} else {
|
||||
insertMap.put("resultCode", "ERROR");
|
||||
}
|
||||
|
||||
insertMap.put("resultMsg", String.valueOf(errorMsg));
|
||||
|
||||
// logHistoryService.insertLogHistory(insertMap, visitLogParamMap);
|
||||
// logHistoryService.insertLogHistory(insertMap, visitLogParamMap);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
@@ -180,7 +179,6 @@ public class WebEventController extends ManagerDraftAction{
|
||||
|
||||
log.debug("WebEventController selectListEvent END");
|
||||
|
||||
|
||||
return HttpUtil.makeHashToJsonModelAndView(map);
|
||||
}
|
||||
|
||||
@@ -191,7 +189,7 @@ public class WebEventController extends ManagerDraftAction{
|
||||
* @param response
|
||||
* @return
|
||||
*/
|
||||
@RequestMapping(value="/webevent/selectEventDetailIntro.do")
|
||||
@RequestMapping(value = "/webevent/selectEventDetailIntro.do")
|
||||
public String selectEventDetailIntro(HttpSession session, HttpServletRequest request, Model model) {
|
||||
|
||||
log.debug("WebEventController selectEventDetailIntro START");
|
||||
@@ -211,8 +209,9 @@ public class WebEventController extends ManagerDraftAction{
|
||||
* @param response
|
||||
* @return
|
||||
*/
|
||||
@RequestMapping(value="/webevent/selectEventDetail.do")
|
||||
public ModelAndView selectEventDetail(HttpSession session, HttpServletRequest request, HttpServletResponse response) {
|
||||
@RequestMapping(value = "/webevent/selectEventDetail.do")
|
||||
public ModelAndView selectEventDetail(HttpSession session, HttpServletRequest request,
|
||||
HttpServletResponse response) {
|
||||
|
||||
log.debug("WebEventController selectEventDetail START");
|
||||
|
||||
@@ -220,24 +219,24 @@ public class WebEventController extends ManagerDraftAction{
|
||||
HashMap<String, Object> map = new HashMap<String, Object>();
|
||||
StringBuffer errorMsg = new StringBuffer();
|
||||
|
||||
try{
|
||||
try {
|
||||
map = webEventService.selectEventDetail(paramMap);
|
||||
log.debug(map + "");
|
||||
}catch (Exception e) {
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
errorMsg.append(e);
|
||||
return null;
|
||||
}finally {
|
||||
if(Constants.OK == map.get("msgCode")) {
|
||||
} finally {
|
||||
if (Constants.OK == map.get("msgCode")) {
|
||||
|
||||
}else{
|
||||
if(null == map.get("msgCode") || ("").equals(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)");
|
||||
if (null == map.get("msgDesc") || ("").equals(map.get("msgDesc"))) {
|
||||
map.put("msgDesc", "정상적으로 수행되지 않았습니다. 관리자에게 문의하시기 바랍니다. (E0029)");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -253,15 +252,15 @@ public class WebEventController extends ManagerDraftAction{
|
||||
insertMap.put("requestValue", String.valueOf(paramMap));
|
||||
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");
|
||||
}else{
|
||||
} else {
|
||||
insertMap.put("resultCode", "ERROR");
|
||||
}
|
||||
|
||||
insertMap.put("resultMsg", String.valueOf(errorMsg));
|
||||
|
||||
// logHistoryService.insertLogHistory(insertMap, visitLogParamMap);
|
||||
// logHistoryService.insertLogHistory(insertMap, visitLogParamMap);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
@@ -269,11 +268,10 @@ public class WebEventController extends ManagerDraftAction{
|
||||
|
||||
log.debug("WebEventController selectEventDetail END");
|
||||
|
||||
|
||||
return HttpUtil.makeHashToJsonModelAndView(map);
|
||||
}
|
||||
|
||||
@RequestMapping(value="/webevent/selectMakeReservation.do")
|
||||
@RequestMapping(value = "/webevent/selectMakeReservation.do")
|
||||
public String selectMakeReservation(HttpSession session, HttpServletRequest request, Model model) {
|
||||
|
||||
log.debug("WebServiceController selectMakeReservation START");
|
||||
@@ -282,214 +280,11 @@ public class WebEventController extends ManagerDraftAction{
|
||||
model.addAttribute("CATEGORY_NO", paramMap.get("CATEGORY_NO"));
|
||||
model.addAttribute("POST_NO", paramMap.get("POST_NO"));
|
||||
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");
|
||||
|
||||
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");
|
||||
|
||||
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);
|
||||
return "/web/service/makeReservation";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpSession;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
|
||||
|
||||
@Slf4j
|
||||
@@ -19,16 +19,16 @@ public class WebHomeController extends ManagerDraftAction{
|
||||
* @param response
|
||||
* @return
|
||||
*/
|
||||
@RequestMapping(value="/")
|
||||
@GetMapping("/")
|
||||
public String homeIntro(HttpSession session,HttpServletRequest request) {
|
||||
|
||||
log.debug("WebHomeController homeIntro START");
|
||||
|
||||
log.debug("WebHomeController homeIntro END");
|
||||
return "/intro";
|
||||
return "/index";
|
||||
}
|
||||
|
||||
@RequestMapping(value="/index")
|
||||
@GetMapping("/index")
|
||||
public String homeIndex(HttpSession session,HttpServletRequest request) {
|
||||
|
||||
log.debug("WebHomeController homeIndex START");
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
package com.madeuhome.controller.web.webreview;
|
||||
|
||||
import com.madeuhome.constants.Constants;
|
||||
import com.madeuhome.init.ManagerDraftAction;
|
||||
import com.madeuhome.service.web.webreview.WebReviewService;
|
||||
import com.madeuhome.util.HttpUtil;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.servlet.http.HttpSession;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
@Slf4j
|
||||
@Controller
|
||||
public class WebReviewController extends ManagerDraftAction {
|
||||
|
||||
@Autowired
|
||||
private WebReviewService webReviewService;
|
||||
|
||||
@RequestMapping(value = "/webreview/selectListProcedureReviewIntro.do")
|
||||
public String selectListProcedureReviewIntro(HttpSession session, HttpServletRequest request) {
|
||||
log.debug("WebReviewController selectListProcedureReviewIntro START");
|
||||
log.debug("WebReviewController selectListProcedureReviewIntro END");
|
||||
return "/web/webreview/procedureReviewSelectList";
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/webreview/selectListProcedureReview.do")
|
||||
public ModelAndView selectListProcedureReview(HttpSession session, HttpServletRequest request,
|
||||
HttpServletResponse response) {
|
||||
log.debug("WebReviewController selectListProcedureReview START");
|
||||
HashMap<String, Object> paramMap = HttpUtil.getParameterMap(request);
|
||||
HashMap<String, Object> map = new HashMap<String, Object>();
|
||||
try {
|
||||
map = webReviewService.selectListProcedureReview(paramMap);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
} finally {
|
||||
if (Constants.OK == map.get("msgCode")) {
|
||||
} else {
|
||||
if (null == map.get("msgCode") || ("").equals(map.get("msgCode"))) {
|
||||
map.put("msgCode", Constants.FAIL);
|
||||
}
|
||||
map.put("success", false);
|
||||
if (null == map.get("msgDesc") || ("").equals(map.get("msgDesc"))) {
|
||||
map.put("msgDesc", "정상적으로 수행되지 않았습니다.");
|
||||
}
|
||||
}
|
||||
}
|
||||
log.debug("WebReviewController selectListProcedureReview END");
|
||||
return HttpUtil.makeHashToJsonModelAndView(map);
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/webreview/selectProcedureReviewIntro.do")
|
||||
public String selectProcedureReviewIntro(HttpSession session, HttpServletRequest request, Model model) {
|
||||
log.debug("WebReviewController selectProcedureReviewIntro START");
|
||||
HashMap<String, Object> paramMap = HttpUtil.getParameterMap(request);
|
||||
model.addAttribute("muProcedureReviewId", paramMap.get("muProcedureReviewId"));
|
||||
log.debug("WebReviewController selectProcedureReviewIntro END");
|
||||
return "/web/webreview/procedureReviewSelect";
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/webreview/selectProcedureReview.do")
|
||||
public ModelAndView selectProcedureReview(HttpSession session, HttpServletRequest request,
|
||||
HttpServletResponse response) {
|
||||
log.debug("WebReviewController selectProcedureReview START");
|
||||
HashMap<String, Object> paramMap = HttpUtil.getParameterMap(request);
|
||||
HashMap<String, Object> map = new HashMap<String, Object>();
|
||||
try {
|
||||
map = webReviewService.selectProcedureReview(paramMap);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
} finally {
|
||||
if (Constants.OK == map.get("msgCode")) {
|
||||
} else {
|
||||
if (null == map.get("msgCode") || ("").equals(map.get("msgCode"))) {
|
||||
map.put("msgCode", Constants.FAIL);
|
||||
}
|
||||
map.put("success", false);
|
||||
if (null == map.get("msgDesc") || ("").equals(map.get("msgDesc"))) {
|
||||
map.put("msgDesc", "정상적으로 수행되지 않았습니다.");
|
||||
}
|
||||
}
|
||||
}
|
||||
log.debug("WebReviewController selectProcedureReview END");
|
||||
return HttpUtil.makeHashToJsonModelAndView(map);
|
||||
}
|
||||
}
|
||||
@@ -25,10 +25,9 @@ import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.servlet.http.HttpSession;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
|
||||
@Slf4j
|
||||
@Controller
|
||||
public class WebServiceController extends ManagerDraftAction{
|
||||
public class WebServiceController extends ManagerDraftAction {
|
||||
@Autowired
|
||||
private WebServiceService webServiceService;
|
||||
|
||||
@@ -39,8 +38,8 @@ public class WebServiceController extends ManagerDraftAction{
|
||||
* @param response
|
||||
* @return
|
||||
*/
|
||||
@RequestMapping(value="/webservice/selectServiceIntro.do")
|
||||
public String selectListServiceIntro(HttpSession session,HttpServletRequest request) {
|
||||
@RequestMapping(value = "/webservice/selectServiceIntro.do")
|
||||
public String selectListServiceIntro(HttpSession session, HttpServletRequest request) {
|
||||
|
||||
log.debug("WebServiceController selectListServiceIntro START");
|
||||
|
||||
@@ -56,8 +55,9 @@ public class WebServiceController extends ManagerDraftAction{
|
||||
* @param response
|
||||
* @return
|
||||
*/
|
||||
@RequestMapping(value="/webservice/selectListCategory.do")
|
||||
public ModelAndView selectListCategory(HttpSession session,HttpServletRequest request, HttpServletResponse response) {
|
||||
@RequestMapping(value = "/webservice/selectListCategory.do")
|
||||
public ModelAndView selectListCategory(HttpSession session, HttpServletRequest request,
|
||||
HttpServletResponse response) {
|
||||
|
||||
log.debug("WebServiceController selectListCategory START");
|
||||
|
||||
@@ -65,24 +65,24 @@ public class WebServiceController extends ManagerDraftAction{
|
||||
HashMap<String, Object> map = new HashMap<String, Object>();
|
||||
StringBuffer errorMsg = new StringBuffer();
|
||||
|
||||
try{
|
||||
try {
|
||||
map = webServiceService.selectListWebCategory(paramMap);
|
||||
log.debug(map + "");
|
||||
}catch (Exception e) {
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
errorMsg.append(e);
|
||||
return null;
|
||||
}finally {
|
||||
if(Constants.OK == map.get("msgCode")) {
|
||||
} finally {
|
||||
if (Constants.OK == map.get("msgCode")) {
|
||||
|
||||
}else{
|
||||
if(null == map.get("msgCode") || ("").equals(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)");
|
||||
if (null == map.get("msgDesc") || ("").equals(map.get("msgDesc"))) {
|
||||
map.put("msgDesc", "정상적으로 수행되지 않았습니다. 관리자에게 문의하시기 바랍니다. (E0029)");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,16 +98,16 @@ public class WebServiceController extends ManagerDraftAction{
|
||||
insertMap.put("requestValue", String.valueOf(paramMap));
|
||||
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");
|
||||
}else{
|
||||
} else {
|
||||
insertMap.put("resultCode", "ERROR");
|
||||
}
|
||||
|
||||
insertMap.put("resultMsg", String.valueOf(errorMsg));
|
||||
insertMap.put("muMemberId", paramMap.get("muMemberId"));
|
||||
|
||||
// logHistoryService.insertLogHistory(insertMap, visitLogParamMap);
|
||||
// logHistoryService.insertLogHistory(insertMap, visitLogParamMap);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
@@ -115,7 +115,6 @@ public class WebServiceController extends ManagerDraftAction{
|
||||
|
||||
log.debug("WebServiceController selectListCategory END");
|
||||
|
||||
|
||||
return HttpUtil.makeHashToJsonModelAndView(map);
|
||||
}
|
||||
|
||||
@@ -126,7 +125,7 @@ public class WebServiceController extends ManagerDraftAction{
|
||||
* @param response
|
||||
* @return
|
||||
*/
|
||||
@PostMapping(value="/webservice/selectListService.do")
|
||||
@PostMapping(value = "/webservice/selectListService.do")
|
||||
@ResponseBody
|
||||
public ResponseEntity<Map<String, Object>> selectListService(@RequestParam("categoryNo") String categoryNo) {
|
||||
|
||||
@@ -155,7 +154,7 @@ public class WebServiceController extends ManagerDraftAction{
|
||||
* @param response
|
||||
* @return
|
||||
*/
|
||||
@RequestMapping(value="/webservice/selectServiceDetailIntro.do")
|
||||
@RequestMapping(value = "/webservice/selectServiceDetailIntro.do")
|
||||
public String selectServiceDetailIntro(HttpSession session, HttpServletRequest request, Model model) {
|
||||
|
||||
log.debug("WebServiceController selectServiceDetailIntro START");
|
||||
@@ -175,8 +174,9 @@ public class WebServiceController extends ManagerDraftAction{
|
||||
* @param response
|
||||
* @return
|
||||
*/
|
||||
@RequestMapping(value="/webservice/selectServiceDetail.do")
|
||||
public ModelAndView selectServiceDetail(HttpSession session, HttpServletRequest request, HttpServletResponse response) {
|
||||
@RequestMapping(value = "/webservice/selectServiceDetail.do")
|
||||
public ModelAndView selectServiceDetail(HttpSession session, HttpServletRequest request,
|
||||
HttpServletResponse response) {
|
||||
|
||||
log.debug("WebServiceController selectServiceDetail START");
|
||||
|
||||
@@ -184,23 +184,23 @@ public class WebServiceController extends ManagerDraftAction{
|
||||
HashMap<String, Object> map = new HashMap<String, Object>();
|
||||
StringBuffer errorMsg = new StringBuffer();
|
||||
|
||||
try{
|
||||
try {
|
||||
map = webServiceService.selectServiceDetail(paramMap);
|
||||
}catch (Exception e) {
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
errorMsg.append(e);
|
||||
return null;
|
||||
}finally {
|
||||
if(Constants.OK == map.get("msgCode")) {
|
||||
} finally {
|
||||
if (Constants.OK == map.get("msgCode")) {
|
||||
|
||||
}else{
|
||||
if(null == map.get("msgCode") || ("").equals(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)");
|
||||
if (null == map.get("msgDesc") || ("").equals(map.get("msgDesc"))) {
|
||||
map.put("msgDesc", "정상적으로 수행되지 않았습니다. 관리자에게 문의하시기 바랍니다. (E0029)");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -216,15 +216,15 @@ public class WebServiceController extends ManagerDraftAction{
|
||||
insertMap.put("requestValue", String.valueOf(paramMap));
|
||||
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");
|
||||
}else{
|
||||
} else {
|
||||
insertMap.put("resultCode", "ERROR");
|
||||
}
|
||||
|
||||
insertMap.put("resultMsg", String.valueOf(errorMsg));
|
||||
|
||||
// logHistoryService.insertLogHistory(insertMap, visitLogParamMap);
|
||||
// logHistoryService.insertLogHistory(insertMap, visitLogParamMap);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
@@ -232,227 +232,6 @@ public class WebServiceController extends ManagerDraftAction{
|
||||
|
||||
log.debug("WebServiceController selectServiceDetail END");
|
||||
|
||||
|
||||
return HttpUtil.makeHashToJsonModelAndView(map);
|
||||
}
|
||||
|
||||
@RequestMapping(value="/webservice/selectMakeReservation.do")
|
||||
public String selectMakeReservation(HttpSession session, HttpServletRequest request, Model model) {
|
||||
|
||||
log.debug("WebServiceController selectMakeReservation START");
|
||||
HashMap<String, Object> paramMap = HttpUtil.getParameterMap(request);
|
||||
model.addAttribute("CATEGORY_DIV_CD", paramMap.get("CATEGORY_DIV_CD"));
|
||||
model.addAttribute("CATEGORY_NO", paramMap.get("CATEGORY_NO"));
|
||||
model.addAttribute("POST_NO", paramMap.get("POST_NO"));
|
||||
model.addAttribute("PROCEDURE_ID", paramMap.get("PROCEDURE_ID"));
|
||||
|
||||
log.debug("WebServiceController selectMakeReservation END");
|
||||
|
||||
return "/web/service/makeReservation";
|
||||
}
|
||||
|
||||
/**
|
||||
* 시술 목록 상세 조회
|
||||
*
|
||||
* @param request
|
||||
* @param response
|
||||
* @return
|
||||
*/
|
||||
@RequestMapping(value="/webservice/selectReservation.do")
|
||||
public ModelAndView selectReservation(HttpSession session, HttpServletRequest request, HttpServletResponse response) {
|
||||
|
||||
log.debug("WebServiceController selectReservation START");
|
||||
|
||||
HashMap<String, Object> paramMap = HttpUtil.getParameterMap(request);
|
||||
HashMap<String, Object> map = new HashMap<String, Object>();
|
||||
StringBuffer errorMsg = new StringBuffer();
|
||||
|
||||
try{
|
||||
map = webServiceService.selectReservation(paramMap);
|
||||
}catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
errorMsg.append(e);
|
||||
return null;
|
||||
}finally {
|
||||
if(Constants.OK == map.get("msgCode")) {
|
||||
|
||||
}else{
|
||||
if(null == map.get("msgCode") || ("").equals(map.get("msgCode"))) {
|
||||
map.put("msgCode", Constants.FAIL);
|
||||
}
|
||||
|
||||
map.put("success", false);
|
||||
if(null == map.get("msgDesc") || ("").equals(map.get("msgDesc"))) {
|
||||
map.put("msgDesc","정상적으로 수행되지 않았습니다. 관리자에게 문의하시기 바랍니다. (E0029)");
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
HashMap<String, Object> visitLogParamMap = RequestLogUtil.getVisitLogParameterMap(request);
|
||||
HashMap<String, Object> insertMap = new HashMap<String, Object>();
|
||||
|
||||
insertMap.put("url", "/webservice/selectReservation.do");
|
||||
insertMap.put("func", "selectListService");
|
||||
insertMap.put("funcName", "예약 조회");
|
||||
insertMap.put("service", "webServiceService");
|
||||
insertMap.put("serviceName", "예약 상세");
|
||||
insertMap.put("requestValue", String.valueOf(paramMap));
|
||||
insertMap.put("responseValue", String.valueOf(map));
|
||||
;
|
||||
if(("true").equals(String.valueOf(map.get("success")))){
|
||||
insertMap.put("resultCode", "SUCCESS");
|
||||
}else{
|
||||
insertMap.put("resultCode", "ERROR");
|
||||
}
|
||||
|
||||
insertMap.put("resultMsg", String.valueOf(errorMsg));
|
||||
|
||||
// logHistoryService.insertLogHistory(insertMap, visitLogParamMap);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
log.debug("WebServiceController selectReservation END");
|
||||
|
||||
|
||||
return HttpUtil.makeHashToJsonModelAndView(map);
|
||||
}
|
||||
|
||||
/**
|
||||
* 시술 목록 상세 조회
|
||||
*
|
||||
* @param request
|
||||
* @param response
|
||||
* @return
|
||||
*/
|
||||
@RequestMapping(value="/webservice/selectReservationCnt.do")
|
||||
public ModelAndView selectReservationCnt(HttpSession session, HttpServletRequest request, HttpServletResponse response) {
|
||||
|
||||
log.debug("WebServiceController selectReservationCnt START");
|
||||
|
||||
HashMap<String, Object> paramMap = HttpUtil.getParameterMap(request);
|
||||
HashMap<String, Object> map = new HashMap<String, Object>();
|
||||
StringBuffer errorMsg = new StringBuffer();
|
||||
|
||||
try{
|
||||
map = webServiceService.selectReservationCnt(paramMap);
|
||||
}catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
errorMsg.append(e);
|
||||
return null;
|
||||
}finally {
|
||||
if(Constants.OK == map.get("msgCode")) {
|
||||
|
||||
}else{
|
||||
if(null == map.get("msgCode") || ("").equals(map.get("msgCode"))) {
|
||||
map.put("msgCode", Constants.FAIL);
|
||||
}
|
||||
|
||||
map.put("success", false);
|
||||
if(null == map.get("msgDesc") || ("").equals(map.get("msgDesc"))) {
|
||||
map.put("msgDesc","정상적으로 수행되지 않았습니다. 관리자에게 문의하시기 바랍니다. (E0029)");
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
HashMap<String, Object> visitLogParamMap = RequestLogUtil.getVisitLogParameterMap(request);
|
||||
HashMap<String, Object> insertMap = new HashMap<String, Object>();
|
||||
|
||||
insertMap.put("url", "/webservice/selectReservationCnt.do");
|
||||
insertMap.put("func", "selectReservationCnt");
|
||||
insertMap.put("funcName", "예약 조회");
|
||||
insertMap.put("service", "webServiceService");
|
||||
insertMap.put("serviceName", "예약 상세");
|
||||
insertMap.put("requestValue", String.valueOf(paramMap));
|
||||
insertMap.put("responseValue", String.valueOf(map));
|
||||
;
|
||||
if(("true").equals(String.valueOf(map.get("success")))){
|
||||
insertMap.put("resultCode", "SUCCESS");
|
||||
}else{
|
||||
insertMap.put("resultCode", "ERROR");
|
||||
}
|
||||
|
||||
insertMap.put("resultMsg", String.valueOf(errorMsg));
|
||||
|
||||
// logHistoryService.insertLogHistory(insertMap, visitLogParamMap);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
log.debug("WebServiceController selectReservationCnt END");
|
||||
|
||||
|
||||
return HttpUtil.makeHashToJsonModelAndView(map);
|
||||
}
|
||||
|
||||
/**
|
||||
* 예약 저장
|
||||
*
|
||||
* @param request
|
||||
* @param response
|
||||
* @return
|
||||
*/
|
||||
@RequestMapping(value="/webservice/insertReservation.do")
|
||||
public ModelAndView insertReservation(HttpSession session, HttpServletRequest request, HttpServletResponse response) {
|
||||
|
||||
log.debug("WebServiceController insertReservation START");
|
||||
|
||||
HashMap<String, Object> paramMap = HttpUtil.getParameterMap(request);
|
||||
HashMap<String, Object> map = new HashMap<String, Object>();
|
||||
StringBuffer errorMsg = new StringBuffer();
|
||||
|
||||
try{
|
||||
map = webServiceService.insertReservation(paramMap);
|
||||
log.debug(map + "TEST");
|
||||
}catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
errorMsg.append(e);
|
||||
return null;
|
||||
}finally {
|
||||
if(Constants.OK == map.get("msgCode")) {
|
||||
|
||||
}else{
|
||||
if(null == map.get("msgCode") || ("").equals(map.get("msgCode"))) {
|
||||
map.put("msgCode", Constants.FAIL);
|
||||
}
|
||||
|
||||
map.put("success", false);
|
||||
if(null == map.get("msgDesc") || ("").equals(map.get("msgDesc"))) {
|
||||
map.put("msgDesc","정상적으로 수행되지 않았습니다. 관리자에게 문의하시기 바랍니다. (E0029)");
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
HashMap<String, Object> visitLogParamMap = RequestLogUtil.getVisitLogParameterMap(request);
|
||||
HashMap<String, Object> insertMap = new HashMap<String, Object>();
|
||||
|
||||
insertMap.put("url", "/webservice/insertReservation.do");
|
||||
insertMap.put("func", "selectReservationCnt");
|
||||
insertMap.put("funcName", "예약 저장");
|
||||
insertMap.put("service", "webServiceService");
|
||||
insertMap.put("serviceName", "예약 저장");
|
||||
insertMap.put("requestValue", String.valueOf(paramMap));
|
||||
insertMap.put("responseValue", String.valueOf(map));
|
||||
;
|
||||
if(("true").equals(String.valueOf(map.get("success")))){
|
||||
insertMap.put("resultCode", "SUCCESS");
|
||||
}else{
|
||||
insertMap.put("resultCode", "ERROR");
|
||||
}
|
||||
|
||||
insertMap.put("resultMsg", String.valueOf(errorMsg));
|
||||
|
||||
// logHistoryService.insertLogHistory(insertMap, visitLogParamMap);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
log.debug("WebServiceController insertReservation END");
|
||||
|
||||
|
||||
return HttpUtil.makeHashToJsonModelAndView(map);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
package com.madeuhome.dao.web.webreview;
|
||||
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import org.mybatis.spring.SqlSessionTemplate;
|
||||
import org.mybatis.spring.support.SqlSessionDaoSupport;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Repository
|
||||
public class WebReviewSqlMapDAO extends SqlSessionDaoSupport {
|
||||
|
||||
@Autowired
|
||||
private SqlSessionTemplate sqlSessionTemplate;
|
||||
|
||||
@PostConstruct
|
||||
void init() {
|
||||
setSqlSessionTemplate(sqlSessionTemplate);
|
||||
}
|
||||
|
||||
public Map<String, Object> selectTotalProcedureReviewCount(HashMap<String, Object> paramMap)
|
||||
throws DataAccessException {
|
||||
return getSqlSession().selectOne("WebReview.selectTotalProcedureReviewCount", paramMap);
|
||||
}
|
||||
|
||||
public List<Map<String, Object>> selectListProcedureReview(HashMap<String, Object> paramMap)
|
||||
throws DataAccessException {
|
||||
return getSqlSession().selectList("WebReview.selectListProcedureReview", paramMap);
|
||||
}
|
||||
|
||||
public Map<String, Object> selectProcedureReview(HashMap<String, Object> paramMap) throws DataAccessException {
|
||||
return getSqlSession().selectOne("WebReview.selectProcedureReview", paramMap);
|
||||
}
|
||||
|
||||
public void updateViewCount(HashMap<String, Object> paramMap) throws DataAccessException {
|
||||
getSqlSession().update("WebReview.updateViewCount", paramMap);
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,7 @@ import org.springframework.stereotype.Repository;
|
||||
import jakarta.annotation.PostConstruct;
|
||||
|
||||
@Repository
|
||||
public class WebServiceSqlMapDAO extends SqlSessionDaoSupport{
|
||||
public class WebServiceSqlMapDAO extends SqlSessionDaoSupport {
|
||||
|
||||
@Autowired
|
||||
private SqlSessionTemplate sqlSessionTemplate;
|
||||
@@ -30,7 +30,8 @@ public class WebServiceSqlMapDAO extends SqlSessionDaoSupport{
|
||||
* @return
|
||||
* @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");
|
||||
|
||||
String sqlId = "WebService.selectListWebCategory";
|
||||
@@ -90,56 +91,4 @@ public class WebServiceSqlMapDAO extends SqlSessionDaoSupport{
|
||||
|
||||
return getSqlSession().selectList(sqlId, paramMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* 예약 상세 조회
|
||||
*
|
||||
* @param Map
|
||||
* @return
|
||||
* @throws DataAccessException
|
||||
*/
|
||||
public Map<String, Object> selectReservationCnt(HashMap<String, Object> paramMap) throws DataAccessException {
|
||||
logger.debug("WebServiceSqlMapDAO selectReservationCnt START");
|
||||
|
||||
String sqlId = "WebService.selectReservationCnt";
|
||||
|
||||
logger.debug("WebServiceSqlMapDAO selectReservationCnt END");
|
||||
|
||||
return getSqlSession().selectOne(sqlId, paramMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* 예약 시술 정보 조회
|
||||
*
|
||||
* @param Map
|
||||
* @return
|
||||
* @throws DataAccessException
|
||||
*/
|
||||
public Map<String, Object> selectReservationService(HashMap<String, Object> paramMap) throws DataAccessException {
|
||||
logger.debug("WebServiceSqlMapDAO selectReservationService START");
|
||||
|
||||
String sqlId = "WebService.selectReservationService";
|
||||
|
||||
logger.debug("WebServiceSqlMapDAO selectReservationService END");
|
||||
|
||||
return getSqlSession().selectOne(sqlId, paramMap);
|
||||
}
|
||||
/**
|
||||
* 예약 정보 저장
|
||||
*
|
||||
* @param Map
|
||||
* @return
|
||||
* @throws DataAccessException
|
||||
*/
|
||||
public Map<String, Object> insertReservation(HashMap<String, Object> paramMap) throws DataAccessException {
|
||||
logger.debug("WebServiceSqlMapDAO insertReservation START");
|
||||
|
||||
String sqlId = "WebService.insertReservation";
|
||||
|
||||
logger.debug("WebServiceSqlMapDAO insertReservation END");
|
||||
|
||||
getSqlSession().insert(sqlId, paramMap);
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
40
src/main/java/com/madeuhome/dto/ReservationDto.java
Normal file
@@ -0,0 +1,40 @@
|
||||
package com.madeuhome.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 예약 관련 DTO
|
||||
*/
|
||||
@Data
|
||||
public class ReservationDto {
|
||||
// 예약 기본 정보
|
||||
private String muReserveId;
|
||||
private String userName;
|
||||
private String phoneNumber;
|
||||
private String birthDate;
|
||||
private String selectedDate;
|
||||
private String time;
|
||||
private String etc;
|
||||
|
||||
// 시술 정보
|
||||
private String categoryDivCd;
|
||||
private String categoryNo;
|
||||
private String postNo;
|
||||
private String procedureId;
|
||||
private String treatmentId;
|
||||
private String treatmentName;
|
||||
private String treatmentProcedureId;
|
||||
private String treatmentProcedureName;
|
||||
private String treatmentInfos;
|
||||
|
||||
// 병원 운영 정보
|
||||
private String muHospitalId;
|
||||
private String hospitalName;
|
||||
private String searchDate;
|
||||
private String openYn;
|
||||
private String holidayYn;
|
||||
private String openStartTime;
|
||||
private String openEndTime;
|
||||
private String breakStartTime;
|
||||
private String breakEndTime;
|
||||
}
|
||||
@@ -0,0 +1,211 @@
|
||||
package com.madeuhome.service.web.reservation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.mybatis.spring.SqlSessionTemplate;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.madeuhome.constants.Constants;
|
||||
import com.madeuhome.util.OkHttpService;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* 예약 서비스 (구현체 포함) - 쁘띠&피부센터
|
||||
*/
|
||||
@Service
|
||||
@Slf4j
|
||||
public class ReservationService {
|
||||
|
||||
@Autowired
|
||||
private SqlSessionTemplate sqlSession;
|
||||
|
||||
@Value("${url.old-crm-php}")
|
||||
private String ocp;
|
||||
|
||||
/**
|
||||
* 예약 시술 정보 조회
|
||||
*/
|
||||
public HashMap<String, Object> selectReservation(HashMap<String, Object> paramMap) throws Exception {
|
||||
log.debug("ReservationService selectReservation START");
|
||||
HashMap<String, Object> map = new HashMap<>();
|
||||
|
||||
try {
|
||||
List<Map<String, Object>> listMap2 = new ArrayList<>();
|
||||
|
||||
if (paramMap.get("PROCEDURE_ID").toString().indexOf(",") != -1) {
|
||||
String[] PROCEDURE_ID = paramMap.get("PROCEDURE_ID").toString().split(",");
|
||||
for (int i = 0; i < PROCEDURE_ID.length; i++) {
|
||||
HashMap<String, Object> map2 = new HashMap<>();
|
||||
map2.put("PROCEDURE_ID", PROCEDURE_ID[i]);
|
||||
listMap2.add(sqlSession.selectOne("Reservation.selectReservationService", map2));
|
||||
}
|
||||
} else {
|
||||
listMap2.add(sqlSession.selectOne("Reservation.selectReservationService", paramMap));
|
||||
}
|
||||
map.put("reservation", listMap2);
|
||||
map.put("msgCode", Constants.OK);
|
||||
map.put("success", "true");
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
throw e;
|
||||
}
|
||||
|
||||
log.debug("ReservationService selectReservation END");
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* 병원 휴일 조회 (달력 표출용)
|
||||
*/
|
||||
public HashMap<String, Object> selectHospitalHolidayList(HashMap<String, Object> paramMap) throws Exception {
|
||||
log.debug("ReservationService selectHospitalHolidayList START");
|
||||
HashMap<String, Object> map = new HashMap<>();
|
||||
|
||||
try {
|
||||
List<Map<String, Object>> listMap = sqlSession.selectList("Reservation.selectHospitalHolidayList",
|
||||
paramMap);
|
||||
map.put("rows", listMap);
|
||||
map.put("msgCode", Constants.OK);
|
||||
map.put("success", "true");
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
throw e;
|
||||
}
|
||||
|
||||
log.debug("ReservationService selectHospitalHolidayList END");
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* 특정 날짜 운영시간 조회
|
||||
*/
|
||||
public HashMap<String, Object> selectHospitalWorkTime(HashMap<String, Object> paramMap) throws Exception {
|
||||
log.debug("ReservationService selectHospitalWorkTime START");
|
||||
HashMap<String, Object> map = new HashMap<>();
|
||||
|
||||
try {
|
||||
Map<String, Object> result = sqlSession.selectOne("Reservation.selectHospitalWorkTime", paramMap);
|
||||
if (result != null) {
|
||||
map.put("rows", result);
|
||||
} else {
|
||||
map.put("rows", new HashMap<>());
|
||||
}
|
||||
map.put("msgCode", Constants.OK);
|
||||
map.put("success", "true");
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
throw e;
|
||||
}
|
||||
|
||||
log.debug("ReservationService selectHospitalWorkTime END");
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* 예약 카운트 조회
|
||||
*/
|
||||
public HashMap<String, Object> selectReservationCnt(HashMap<String, Object> paramMap) throws Exception {
|
||||
log.debug("ReservationService selectReservationCnt START");
|
||||
HashMap<String, Object> map = new HashMap<>();
|
||||
|
||||
try {
|
||||
Map<String, Object> result = sqlSession.selectOne("Reservation.selectReservationCnt", paramMap);
|
||||
map.put("rows", result);
|
||||
map.put("msgCode", Constants.OK);
|
||||
map.put("success", "true");
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
throw e;
|
||||
}
|
||||
|
||||
log.debug("ReservationService selectReservationCnt END");
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* 예약 저장
|
||||
*/
|
||||
public HashMap<String, Object> insertReservation(HashMap<String, Object> paramMap) throws Exception {
|
||||
log.debug("ReservationService insertReservation START");
|
||||
HashMap<String, Object> map = new HashMap<>();
|
||||
try {
|
||||
String muReserveId = ("R").concat(String.valueOf(System.currentTimeMillis()));
|
||||
paramMap.put("muReserveId", muReserveId);
|
||||
ArrayList<String> userRequest = new ArrayList<>();
|
||||
|
||||
// TREATMENT_INFOS 파라미터가 있으면 파싱하여 P_변수명으로 세팅 후 insertReservation 호출
|
||||
if (paramMap.get("TREATMENT_INFOS") != null) {
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
List<Map<String, Object>> treatmentList = objectMapper.readValue(
|
||||
paramMap.get("TREATMENT_INFOS").toString(),
|
||||
new TypeReference<List<Map<String, Object>>>() {
|
||||
});
|
||||
for (Map<String, Object> t : treatmentList) {
|
||||
paramMap.put("P_TREATMENT_ID", t.get("MU_TREATMENT_ID"));
|
||||
paramMap.put("P_TREATMENT_NM", t.get("TREATMENT_NAME"));
|
||||
paramMap.put("P_PROCEDURE_ID", t.get("MU_TREATMENT_PROCEDURE_ID"));
|
||||
paramMap.put("P_PROCEDURE_NM", t.get("TREATMENT_PROCEDURE_NAME"));
|
||||
userRequest.add((String) t.get("TREATMENT_PROCEDURE_NAME"));
|
||||
sqlSession.insert("Reservation.insertReservation", paramMap);
|
||||
}
|
||||
} else {
|
||||
// 기존 방식대로 단일 시술 정보로 처리
|
||||
paramMap.put("P_TREATMENT_ID", paramMap.get("MU_TREATMENT_ID"));
|
||||
paramMap.put("P_TREATMENT_NM", paramMap.get("TREATMENT_NAME"));
|
||||
paramMap.put("P_PROCEDURE_ID", paramMap.get("MU_TREATMENT_PROCEDURE_ID"));
|
||||
paramMap.put("P_PROCEDURE_NM", paramMap.get("TREATMENT_PROCEDURE_NAME"));
|
||||
userRequest.add((String) paramMap.get("TREATMENT_PROCEDURE_NAME"));
|
||||
sqlSession.insert("Reservation.insertReservation", paramMap);
|
||||
}
|
||||
|
||||
Map<String, String> formData = new HashMap<>();
|
||||
formData.put("visitorName", (String) paramMap.get("NAME"));
|
||||
formData.put("visitorPhone", (String) paramMap.get("PHONE_NUMBER"));
|
||||
|
||||
String strUserRequest = "[선택시술]:" + userRequest.stream().collect(Collectors.joining(", "));
|
||||
String birthDate = "[생년월일]:" + paramMap.get("BIRTH_DATE");
|
||||
String reqTxt = "[요청사항]:" + (String) paramMap.get("ETC");
|
||||
formData.put("userRequest", strUserRequest + "\n" + birthDate + "\n" + reqTxt);
|
||||
String time = (String) paramMap.get("TIME");
|
||||
String date = (String) paramMap.get("SELECTED_DATE");
|
||||
String dateTime = date + " " + time;
|
||||
formData.put("datetime", dateTime);
|
||||
|
||||
Map<String, Object> detailMap = sqlSession.selectOne("Reservation.selectServiceDetail", paramMap);
|
||||
|
||||
formData.put("itemName", "[홈페이지] 쁘띠&피부센터");
|
||||
// 구CRM 연동ID가 없을 경우 기본값 (피부 & 쁘띠센터)
|
||||
String oldCrmItemId = (String) detailMap.get("oldCrmItemId") == null
|
||||
? "NBI-4aJSJ67P-f0ID-4xds-aReQ-MnhfErLts0HP"
|
||||
: (String) detailMap.get("oldCrmItemId");
|
||||
formData.put("itemID", oldCrmItemId);
|
||||
formData.put("etcText", "[진료]:" + (String) detailMap.get("CATEGORY_NM"));
|
||||
|
||||
// OLD CRM으로 예약정보 POST
|
||||
OkHttpService.postFormData(ocp, formData);
|
||||
|
||||
map.put("msgCode", Constants.OK);
|
||||
map.put("success", "true");
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
throw e;
|
||||
}
|
||||
|
||||
log.debug("ReservationService insertReservation END");
|
||||
return map;
|
||||
}
|
||||
}
|
||||
@@ -36,7 +36,7 @@ public class WebInstagramServiceImpl implements WebInstagramService {
|
||||
HashMap<String, Object> paramMap) throws Exception {
|
||||
log.debug("WebInstagramServiceImpl selectListWebInstagram START");
|
||||
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{
|
||||
RestTemplate restTemplate = new RestTemplate();
|
||||
Map<String, Object> response = restTemplate.getForObject(apiUrl, Map.class);
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.madeuhome.service.web.webreview;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
public interface WebReviewService {
|
||||
public HashMap<String, Object> selectListProcedureReview(HashMap<String, Object> paramMap) throws Exception;
|
||||
|
||||
public HashMap<String, Object> selectProcedureReview(HashMap<String, Object> paramMap) throws Exception;
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package com.madeuhome.service.web.webreview.impl;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.madeuhome.constants.Constants;
|
||||
import com.madeuhome.dao.web.webreview.WebReviewSqlMapDAO;
|
||||
import com.madeuhome.service.web.webreview.WebReviewService;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
@Service("WebReviewService")
|
||||
public class WebReviewServiceImpl implements WebReviewService {
|
||||
|
||||
@Autowired
|
||||
private WebReviewSqlMapDAO webReviewSqlMapDAO;
|
||||
|
||||
@Override
|
||||
public HashMap<String, Object> selectListProcedureReview(HashMap<String, Object> paramMap) throws Exception {
|
||||
log.debug("WebReviewServiceImpl selectListProcedureReview START");
|
||||
HashMap<String, Object> map = new HashMap<String, Object>();
|
||||
try {
|
||||
Map<String, Object> totalMap = webReviewSqlMapDAO.selectTotalProcedureReviewCount(paramMap);
|
||||
map.put("totalCount", totalMap.get("totalCount"));
|
||||
List<Map<String, Object>> listMap = webReviewSqlMapDAO.selectListProcedureReview(paramMap);
|
||||
map.put("rows", listMap);
|
||||
map.put("msgCode", Constants.OK);
|
||||
map.put("success", "true");
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
throw e;
|
||||
}
|
||||
log.debug("WebReviewServiceImpl selectListProcedureReview END");
|
||||
return map;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HashMap<String, Object> selectProcedureReview(HashMap<String, Object> paramMap) throws Exception {
|
||||
log.debug("WebReviewServiceImpl selectProcedureReview START");
|
||||
HashMap<String, Object> map = new HashMap<String, Object>();
|
||||
try {
|
||||
webReviewSqlMapDAO.updateViewCount(paramMap);
|
||||
Map<String, Object> detailMap = webReviewSqlMapDAO.selectProcedureReview(paramMap);
|
||||
map.put("rows", detailMap);
|
||||
map.put("msgCode", Constants.OK);
|
||||
map.put("success", "true");
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
throw e;
|
||||
}
|
||||
log.debug("WebReviewServiceImpl selectProcedureReview END");
|
||||
return map;
|
||||
}
|
||||
}
|
||||
@@ -4,9 +4,8 @@ import java.util.HashMap;
|
||||
|
||||
public interface WebServiceService {
|
||||
public 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> 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,35 +1,25 @@
|
||||
package com.madeuhome.service.web.webservice.impl;
|
||||
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
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.dao.web.webservice.WebServiceSqlMapDAO;
|
||||
import com.madeuhome.service.web.webservice.WebServiceService;
|
||||
import com.madeuhome.util.OkHttpService;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
@Service("WebServiceService")
|
||||
public class WebServiceServiceImpl implements WebServiceService{
|
||||
public class WebServiceServiceImpl implements WebServiceService {
|
||||
|
||||
@Autowired
|
||||
private WebServiceSqlMapDAO webServiceSqlMapDAO;
|
||||
|
||||
@Value("${url.old-crm-php}")
|
||||
private String ocp;
|
||||
|
||||
/**
|
||||
* 시술 정보 카테고리 리스트 조회 (List)
|
||||
*
|
||||
@@ -43,14 +33,14 @@ public class WebServiceServiceImpl implements WebServiceService{
|
||||
|
||||
HashMap<String, Object> map = new HashMap<String, Object>();
|
||||
|
||||
try{
|
||||
try {
|
||||
List<Map<String, Object>> listMap = webServiceSqlMapDAO.selectListWebCategory(paramMap);
|
||||
map.put("rows",listMap);
|
||||
map.put("rows", listMap);
|
||||
|
||||
map.put("msgCode", Constants.OK);
|
||||
map.put("success","true");
|
||||
map.put("success", "true");
|
||||
|
||||
}catch (Exception e) {
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
throw e;
|
||||
}
|
||||
@@ -72,14 +62,14 @@ public class WebServiceServiceImpl implements WebServiceService{
|
||||
|
||||
HashMap<String, Object> map = new HashMap<String, Object>();
|
||||
|
||||
try{
|
||||
try {
|
||||
List<Map<String, Object>> listMap = webServiceSqlMapDAO.selectListWebService(paramMap);
|
||||
map.put("rows",listMap);
|
||||
map.put("rows", listMap);
|
||||
|
||||
map.put("msgCode", Constants.OK);
|
||||
map.put("success","true");
|
||||
map.put("success", "true");
|
||||
|
||||
}catch (Exception e) {
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
throw e;
|
||||
}
|
||||
@@ -101,18 +91,18 @@ public class WebServiceServiceImpl implements WebServiceService{
|
||||
|
||||
HashMap<String, Object> map = new HashMap<String, Object>();
|
||||
|
||||
try{
|
||||
//상세 내용
|
||||
try {
|
||||
// 상세 내용
|
||||
Map<String, Object> listMap = webServiceSqlMapDAO.selectServiceDetail(paramMap);
|
||||
map.put("rows",listMap);
|
||||
//시술 목록
|
||||
map.put("rows", listMap);
|
||||
// 시술 목록
|
||||
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");
|
||||
map.put("success", "true");
|
||||
|
||||
}catch (Exception e) {
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
throw e;
|
||||
}
|
||||
@@ -120,176 +110,4 @@ public class WebServiceServiceImpl implements WebServiceService{
|
||||
log.debug("WebServiceServiceImpl selectServiceDetail END");
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* 예약 정보 조회
|
||||
*
|
||||
* @param paramMap
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@Override
|
||||
public HashMap<String, Object> selectReservation(HashMap<String, Object> paramMap) throws Exception {
|
||||
log.debug("WebServiceServiceImpl selectReservation START");
|
||||
HashMap<String, Object> map = new HashMap<String, Object>();
|
||||
|
||||
try{
|
||||
//예약 목록
|
||||
List<Map<String, Object>> listMap2 = new ArrayList<Map<String, Object>>();
|
||||
|
||||
if(paramMap.get("PROCEDURE_ID").toString().indexOf(",") != -1) {
|
||||
String[] PROCEDURE_ID = paramMap.get("PROCEDURE_ID").toString().split(",");
|
||||
|
||||
for(int i = 0; i < PROCEDURE_ID.length; i++) {
|
||||
HashMap<String, Object> map2 = new HashMap<String, Object>();
|
||||
map2.put("PROCEDURE_ID", PROCEDURE_ID[i]);
|
||||
listMap2.add(webServiceSqlMapDAO.selectReservationService(map2));
|
||||
}
|
||||
}else {
|
||||
listMap2.add(webServiceSqlMapDAO.selectReservationService(paramMap));
|
||||
}
|
||||
map.put("reservation",listMap2);
|
||||
map.put("msgCode", Constants.OK);
|
||||
map.put("success","true");
|
||||
|
||||
}catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
throw e;
|
||||
}
|
||||
|
||||
log.debug("WebServiceServiceImpl selectReservation END");
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* 예약 정보 조회
|
||||
*
|
||||
* @param paramMap
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@Override
|
||||
public HashMap<String, Object> selectReservationCnt(HashMap<String, Object> paramMap) throws Exception {
|
||||
log.debug("WebServiceServiceImpl selectReservationCnt START");
|
||||
|
||||
HashMap<String, Object> map = new HashMap<String, Object>();
|
||||
|
||||
try{
|
||||
//상세 내용
|
||||
Map<String, Object> listMap = webServiceSqlMapDAO.selectReservationCnt(paramMap);
|
||||
map.put("rows",listMap);
|
||||
|
||||
map.put("msgCode", Constants.OK);
|
||||
map.put("success","true");
|
||||
|
||||
}catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
throw e;
|
||||
}
|
||||
|
||||
log.debug("WebServiceServiceImpl selectReservationCnt END");
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* 예약 정보 저장
|
||||
*
|
||||
* @param paramMap
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@Override
|
||||
public HashMap<String, Object> insertReservation(HashMap<String, Object> paramMap) throws Exception {
|
||||
log.debug("WebServiceServiceImpl insertReservation START");
|
||||
HashMap<String, Object> map = new HashMap<String, Object>();
|
||||
try{
|
||||
String muReserveId = ("R").concat(String.valueOf(System.currentTimeMillis()));
|
||||
paramMap.put("muReserveId",muReserveId);
|
||||
ArrayList<String> userRequest = new ArrayList<String>();
|
||||
// TREATMENT_INFOS 파라미터가 있으면 파싱하여 P_변수명으로 세팅 후 insertReservation 호출
|
||||
if(paramMap.get("TREATMENT_INFOS") != null) {
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
List<Map<String, Object>> treatmentList = objectMapper.readValue(paramMap.get("TREATMENT_INFOS").toString(), new TypeReference<List<Map<String, Object>>>(){});
|
||||
for(Map<String, Object> t : treatmentList) {
|
||||
paramMap.put("P_TREATMENT_ID", t.get("MU_TREATMENT_ID"));
|
||||
paramMap.put("P_TREATMENT_NM", t.get("TREATMENT_NAME"));
|
||||
paramMap.put("P_PROCEDURE_ID", t.get("MU_TREATMENT_PROCEDURE_ID"));
|
||||
paramMap.put("P_PROCEDURE_NM", t.get("TREATMENT_PROCEDURE_NAME"));
|
||||
userRequest.add((String) t.get("TREATMENT_PROCEDURE_NAME"));
|
||||
webServiceSqlMapDAO.insertReservation(paramMap);
|
||||
}
|
||||
} else {
|
||||
// 기존 방식대로 단일 시술 정보로 처리
|
||||
paramMap.put("P_TREATMENT_ID", paramMap.get("MU_TREATMENT_ID"));
|
||||
paramMap.put("P_TREATMENT_NM", paramMap.get("TREATMENT_NAME"));
|
||||
paramMap.put("P_PROCEDURE_ID", paramMap.get("MU_TREATMENT_PROCEDURE_ID"));
|
||||
paramMap.put("P_PROCEDURE_NM", paramMap.get("TREATMENT_PROCEDURE_NAME"));
|
||||
userRequest.add((String) paramMap.get("TREATMENT_PROCEDURE_NAME"));
|
||||
webServiceSqlMapDAO.insertReservation(paramMap);
|
||||
}
|
||||
|
||||
Map<String, String> formData = new HashMap<>();
|
||||
formData.put("visitorName", (String) paramMap.get("NAME"));
|
||||
formData.put("visitorPhone", (String) paramMap.get("PHONE_NUMBER"));
|
||||
|
||||
String strUserRequest = "[선택시술]:" + userRequest.stream().collect(Collectors.joining(", "));
|
||||
String birthDate = "[생년월일]:" + paramMap.get("BIRTH_DATE");
|
||||
String reqTxt = "[요청사항]:" + (String) paramMap.get("ETC");
|
||||
formData.put("userRequest", strUserRequest + "\n" + birthDate + "\n" + reqTxt);
|
||||
String time = (String) paramMap.get("TIME");
|
||||
String date = (String) paramMap.get("SELECTED_DATE");
|
||||
String dateTime = date + " " + time;
|
||||
formData.put("datetime", dateTime);
|
||||
|
||||
Map<String, Object> detailMap = webServiceSqlMapDAO.selectServiceDetail(paramMap);
|
||||
|
||||
formData.put("itemName", "[홈페이지] 쁘띠&피부센터");
|
||||
// 구CRM 연동ID가 없을 경우 모두 (재방문) 다이어트 센터
|
||||
String oldCrmItemId = (String) detailMap.get("oldCrmItemId") == null ? "NBI-4aJSJ67P-f0ID-4xds-aReQ-MnhfErLts0HP" : (String) detailMap.get("oldCrmItemId");
|
||||
formData.put("itemID", oldCrmItemId);
|
||||
|
||||
formData.put("etcText", "[진료]:" + (String) detailMap.get("CATEGORY_NM"));
|
||||
|
||||
// OLD CRM으로 예약정보 POST
|
||||
/**
|
||||
* //시술정보(상품명 , 상품ID)
|
||||
상품명 : 메쉬다주사(지방분해주사)
|
||||
상품 ID : NBI-1M0JEq5C-b8LM-4W0V-9YxZ-Z5r9XWJpIVEZ
|
||||
|
||||
피부 & 쁘띠센터
|
||||
NBI-4aJSJ67P-f0ID-4xds-aReQ-MnhfErLts0HP
|
||||
|
||||
프리미엄 레이저 리프팅
|
||||
NBI-1iPCWjih-2TDk-4NG3-ci56-tK7dgxxAT6dU
|
||||
|
||||
(첫방문) 다이어트 센터
|
||||
NBI-1Q8doiCm-qzTh-4imi-9lsK-6YDslUzIK2OO
|
||||
|
||||
(재방문) 다이어트 센터
|
||||
NBI-2WlrXQdl-esws-5aA5-al7z-d7HwxL9tX0YF
|
||||
|
||||
탈모약
|
||||
NBI-Nz00si0r-DkGc-5hdd-bs27-SLn0KHlHflS8
|
||||
|
||||
비만치료제 위고비
|
||||
NBI-2nJnTFVm-ieDy-4TNQ-czDK-Ll9FyixFr7zn
|
||||
|
||||
*
|
||||
*
|
||||
**/
|
||||
OkHttpService.postFormData(ocp, formData);
|
||||
|
||||
|
||||
map.put("msgCode", Constants.OK);
|
||||
map.put("success","true");
|
||||
|
||||
}catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
throw e;
|
||||
}
|
||||
|
||||
System.out.println("[insertReservation] paramMap: " + paramMap);
|
||||
log.debug("WebServiceServiceImpl insertReservation END");
|
||||
return map;
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@ spring:
|
||||
password: madeu12#$
|
||||
|
||||
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
|
||||
|
||||
madeu:
|
||||
|
||||
@@ -2,12 +2,12 @@ spring:
|
||||
datasource:
|
||||
hikari:
|
||||
driver-class-name: org.mariadb.jdbc.Driver
|
||||
jdbc-url: jdbc:mariadb://vara.iptime.org:3306/madeu
|
||||
jdbc-url: jdbc:mariadb://183.98.184.84:3306/madeu
|
||||
username: madeu
|
||||
password: madeu12#$
|
||||
password: apdlemdb12#$
|
||||
|
||||
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
|
||||
|
||||
madeu:
|
||||
|
||||
@@ -7,7 +7,7 @@ spring:
|
||||
password: apdlemdb12#$
|
||||
|
||||
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
|
||||
|
||||
madeu:
|
||||
|
||||
@@ -50,4 +50,4 @@ senderPhoneNumber: 025474711
|
||||
# Instagram 설정
|
||||
instagram:
|
||||
client-id: 17841400162629727
|
||||
accesstoken: IGAAMzYDUuoLJBZAFBieGZAYWXplcjlkRGZAkenkxbDEtSWp0VDkxZA2VEOGljcndKR2NMWl9FQmNGUVlMTzZAkbWgxd0xjRXJlTjNhanB4VWxIX2tZARnhuZATUycEFoLVZAvbUtQam11blEzbDR6QmpjQVBBSm5wc0JKdnIyc2xxVVRrNAZDZD
|
||||
accesstoken: EAAbtjekAF1EBQaZAZAmZCW8TyAA176J5yD6tFSj4MaZACgROAxGsvvT0cSvPxqLOHR4Bd8EeHSvWAqHZB8nHxurf3s3z0vtXt8sQ4zZBHpEJcnNTWSOvfch7hXv4uOQcfliBZCL6dDhMukAtgmXRHlfJasKDc5cZBcI7AuqNr1BZB0jUAwPC8uMUiIQ8dFjpRbnVyRwZDZD
|
||||
|
||||
240
src/main/resources/mappers/ReservationMapper.xml
Normal file
@@ -0,0 +1,240 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="Reservation">
|
||||
|
||||
<!-- 병원 휴일 조회 (달력 표출용) -->
|
||||
<select id="selectHospitalHolidayList" parameterType="hashmap" resultType="hashmap">
|
||||
SELECT 'hospitalHoliday' AS "dateType"
|
||||
, HOSPITAL_HOLIDAY_NAME AS "hospitalHolidayName"
|
||||
, DATE_FORMAT(LOC_DATE, '%Y-%m-%d') AS "locDate"
|
||||
FROM MU_HOSPITAL_HOLIDAY MH
|
||||
WHERE MH.USE_YN = 'Y'
|
||||
AND MH.MU_HOSPITAL_ID = (SELECT MU_HOSPITAL_ID FROM MU_HOSPITAL WHERE USE_YN='Y' AND CENTER_DIV_CD='PETIT' LIMIT 1)
|
||||
AND (
|
||||
(MH.REPEAT_YN = 'Y')
|
||||
OR
|
||||
(MH.REPEAT_YN = 'N' AND DATE_FORMAT( MH.LOC_DATE, '%Y' ) >= DATE_FORMAT( CURDATE( ), '%Y' ))
|
||||
)
|
||||
UNION ALL
|
||||
(
|
||||
SELECT 'publicHoliday' AS "dateType"
|
||||
, MPH.PUBLIC_HOLIDAY_NAME AS "publicHolidayName"
|
||||
, DATE_FORMAT(MPH.LOC_DATE, '%Y-%m-%d') AS "locDate"
|
||||
FROM MU_PUBLIC_HOLIDAY MPH
|
||||
JOIN MU_HOSPITAL MH
|
||||
ON MH.MU_HOSPITAL_ID = (SELECT MU_HOSPITAL_ID FROM MU_HOSPITAL WHERE USE_YN='Y' AND CENTER_DIV_CD='PETIT' LIMIT 1)
|
||||
AND MH.PUBLIC_HOLIDAY_USE_YN = 'Y'
|
||||
WHERE MPH.USE_YN = 'Y'
|
||||
AND DATE_FORMAT( MPH.LOC_DATE, '%Y' ) >= DATE_FORMAT( CURDATE( ), '%Y' )
|
||||
)
|
||||
UNION ALL
|
||||
(
|
||||
SELECT CASE WHEN OPEN_YN = 'Y' THEN 'hospitalScheduleOpen' ELSE 'hospitalSchedule' END AS "dateType"
|
||||
, CASE WHEN OPEN_YN = 'Y' THEN '운영' ELSE '휴무' END AS "hospitalHolidayName"
|
||||
, DATE_FORMAT(SCHEDULE_DATE, '%Y-%m-%d') AS "locDate"
|
||||
FROM MU_HOSPITAL_SCHEDULE
|
||||
WHERE MU_HOSPITAL_ID = (SELECT MU_HOSPITAL_ID FROM MU_HOSPITAL WHERE USE_YN='Y' AND CENTER_DIV_CD='PETIT' LIMIT 1)
|
||||
AND USE_YN = 'Y'
|
||||
AND DATE_FORMAT( SCHEDULE_DATE, '%Y' ) >= DATE_FORMAT( CURDATE( ), '%Y' )
|
||||
)
|
||||
</select>
|
||||
|
||||
<!-- 특정 날짜 운영시간 조회 -->
|
||||
<select id="selectHospitalWorkTime" parameterType="hashmap" resultType="hashmap">
|
||||
SELECT MH.MU_HOSPITAL_ID AS "muHospitalId"
|
||||
,MH.HOSPITAL_NAME AS "hospitalName"
|
||||
,CASE
|
||||
WHEN MHS.MU_HOSPITAL_SCHEDULE_ID IS NOT NULL THEN MHS.OPEN_YN
|
||||
ELSE
|
||||
CASE DAYOFWEEK(#{searchDate})
|
||||
WHEN 2 THEN MH.MON_OPEN_YN
|
||||
WHEN 3 THEN MH.TUE_OPEN_YN
|
||||
WHEN 4 THEN MH.WED_OPEN_YN
|
||||
WHEN 5 THEN MH.THU_OPEN_YN
|
||||
WHEN 6 THEN MH.FRI_OPEN_YN
|
||||
WHEN 7 THEN MH.SAT_OPEN_YN
|
||||
WHEN 1 THEN MH.SUN_OPEN_YN
|
||||
END
|
||||
END AS "openYn"
|
||||
,CASE
|
||||
WHEN MHS.MU_HOSPITAL_SCHEDULE_ID IS NOT NULL AND MHS.OPEN_YN = 'Y' THEN 'N'
|
||||
WHEN MHS.MU_HOSPITAL_SCHEDULE_ID IS NOT NULL AND MHS.OPEN_YN = 'N' THEN 'Y'
|
||||
WHEN EXISTS (
|
||||
SELECT 1
|
||||
FROM MU_HOSPITAL_HOLIDAY HH
|
||||
WHERE HH.USE_YN = 'Y'
|
||||
AND HH.MU_HOSPITAL_ID = MH.MU_HOSPITAL_ID
|
||||
AND (
|
||||
(HH.REPEAT_YN = 'Y' AND DATE_FORMAT(HH.LOC_DATE, '%m-%d') = DATE_FORMAT(#{searchDate}, '%m-%d'))
|
||||
OR
|
||||
(HH.REPEAT_YN = 'N' AND HH.LOC_DATE = #{searchDate})
|
||||
)) OR
|
||||
EXISTS (
|
||||
SELECT 1
|
||||
FROM MU_PUBLIC_HOLIDAY MPH
|
||||
WHERE MPH.USE_YN = 'Y'
|
||||
AND MH.PUBLIC_HOLIDAY_USE_YN='Y'
|
||||
AND MPH.LOC_DATE = #{searchDate}
|
||||
)
|
||||
THEN 'Y'
|
||||
ELSE 'N'
|
||||
END AS "holidayYn"
|
||||
,CASE
|
||||
WHEN MHS.MU_HOSPITAL_SCHEDULE_ID IS NOT NULL THEN MHS.OPEN_START_TIME
|
||||
ELSE
|
||||
CASE DAYOFWEEK(#{searchDate})
|
||||
WHEN 2 THEN MH.MON_OPEN_START_TIME
|
||||
WHEN 3 THEN MH.TUE_OPEN_START_TIME
|
||||
WHEN 4 THEN MH.WED_OPEN_START_TIME
|
||||
WHEN 5 THEN MH.THU_OPEN_START_TIME
|
||||
WHEN 6 THEN MH.FRI_OPEN_START_TIME
|
||||
WHEN 7 THEN MH.SAT_OPEN_START_TIME
|
||||
WHEN 1 THEN MH.SUN_OPEN_START_TIME
|
||||
END
|
||||
END AS "openStartTime"
|
||||
,CASE
|
||||
WHEN MHS.MU_HOSPITAL_SCHEDULE_ID IS NOT NULL THEN MHS.OPEN_END_TIME
|
||||
ELSE
|
||||
CASE DAYOFWEEK(#{searchDate})
|
||||
WHEN 2 THEN MH.MON_OPEN_END_TIME
|
||||
WHEN 3 THEN MH.TUE_OPEN_END_TIME
|
||||
WHEN 4 THEN MH.WED_OPEN_END_TIME
|
||||
WHEN 5 THEN MH.THU_OPEN_END_TIME
|
||||
WHEN 6 THEN MH.FRI_OPEN_END_TIME
|
||||
WHEN 7 THEN MH.SAT_OPEN_END_TIME
|
||||
WHEN 1 THEN MH.SUN_OPEN_END_TIME
|
||||
END
|
||||
END AS "openEndTime"
|
||||
,CASE
|
||||
WHEN MHS.MU_HOSPITAL_SCHEDULE_ID IS NOT NULL THEN MHS.BREAK_START_TIME
|
||||
ELSE
|
||||
CASE DAYOFWEEK(#{searchDate})
|
||||
WHEN 2 THEN MH.MON_BREAK_START_TIME
|
||||
WHEN 3 THEN MH.TUE_BREAK_START_TIME
|
||||
WHEN 4 THEN MH.WED_BREAK_START_TIME
|
||||
WHEN 5 THEN MH.THU_BREAK_START_TIME
|
||||
WHEN 6 THEN MH.FRI_BREAK_START_TIME
|
||||
WHEN 7 THEN MH.SAT_BREAK_START_TIME
|
||||
WHEN 1 THEN MH.SUN_BREAK_START_TIME
|
||||
END
|
||||
END AS "breakStartTime"
|
||||
,CASE
|
||||
WHEN MHS.MU_HOSPITAL_SCHEDULE_ID IS NOT NULL THEN MHS.BREAK_END_TIME
|
||||
ELSE
|
||||
CASE DAYOFWEEK(#{searchDate})
|
||||
WHEN 2 THEN MH.MON_BREAK_END_TIME
|
||||
WHEN 3 THEN MH.TUE_BREAK_END_TIME
|
||||
WHEN 4 THEN MH.WED_BREAK_END_TIME
|
||||
WHEN 5 THEN MH.THU_BREAK_END_TIME
|
||||
WHEN 6 THEN MH.FRI_BREAK_END_TIME
|
||||
WHEN 7 THEN MH.SAT_BREAK_END_TIME
|
||||
WHEN 1 THEN MH.SUN_BREAK_END_TIME
|
||||
END
|
||||
END AS "breakEndTime"
|
||||
,MH.PUBLIC_HOLIDAY_USE_YN AS "publicHolidayUseYn"
|
||||
FROM MU_HOSPITAL AS MH
|
||||
LEFT JOIN MU_HOSPITAL_SCHEDULE MHS
|
||||
ON MH.MU_HOSPITAL_ID = MHS.MU_HOSPITAL_ID
|
||||
AND MHS.SCHEDULE_DATE = #{searchDate}
|
||||
AND MHS.USE_YN = 'Y'
|
||||
WHERE MH.USE_YN = 'Y'
|
||||
AND MH.CENTER_DIV_CD = 'PETIT'
|
||||
LIMIT 0, 1
|
||||
</select>
|
||||
|
||||
<!-- 예약 카운트 조회 -->
|
||||
<select id="selectReservationCnt" resultType="hashmap" parameterType="hashmap">
|
||||
SELECT COUNT(*) AS RES_CNT
|
||||
FROM MU_RESERVE
|
||||
WHERE RESERVE_DATE = #{SELECTED_DATE}
|
||||
AND RESERVE_TIME = #{TIME}
|
||||
</select>
|
||||
|
||||
<!-- 예약 시술 정보 조회 -->
|
||||
<select id="selectReservationService" resultType="hashmap" parameterType="hashmap">
|
||||
SELECT A.TREATMENT_PROCEDURE_NAME, (B.PRICE + B.VAT) AS PRICE, B.VAT, B.DISCOUNT_PRICE, C.MU_TREATMENT_ID, C.TREATMENT_NAME, B.MU_TREATMENT_PROCEDURE_ID
|
||||
FROM MU_TREATMENT_PROCEDURE A
|
||||
LEFT OUTER JOIN MU_TREATMENT_PROCEDURE_PRICE B ON A.MU_TREATMENT_PROCEDURE_ID = B.MU_TREATMENT_PROCEDURE_ID AND B.USE_YN = 'Y'
|
||||
LEFT OUTER JOIN MU_TREATMENT C ON A.MU_TREATMENT_ID = C.MU_TREATMENT_ID
|
||||
WHERE A.MU_TREATMENT_PROCEDURE_ID = #{PROCEDURE_ID}
|
||||
</select>
|
||||
|
||||
<!-- 시술 상세 조회 (CRM 연동용) -->
|
||||
<select id="selectServiceDetail" resultType="hashmap" parameterType="hashmap">
|
||||
SELECT A.CATEGORY_DIV_CD
|
||||
, A.CATEGORY_NO
|
||||
, A.POST_NO
|
||||
, C.CATEGORY_NM
|
||||
, A.TITLE
|
||||
, A.CONTENT
|
||||
, A.THUMBNAIL_BOTTOM_TXT
|
||||
, A.HASHTAG
|
||||
, A.OLD_CRM_ITEM_ID as oldCrmItemId
|
||||
, D.FILE_PATH AS THUMBNAIL_PATH
|
||||
, E.FILE_PATH AS CONTENTS_PATH
|
||||
, (SELECT MIN(PRICE + VAT) FROM MU_TREATMENT_PROCEDURE_PRICE C
|
||||
LEFT OUTER JOIN HP_CONTENTS_BBS_PROCEDURE B ON A.POST_NO = B.POST_NO AND A.CATEGORY_DIV_CD = B.CATEGORY_DIV_CD AND A.CATEGORY_NO = B.CATEGORY_NO AND B.USE_YN = 'Y'
|
||||
WHERE B.MU_TREATMENT_PROCEDURE_ID = C.MU_TREATMENT_PROCEDURE_ID AND C.USE_YN = 'Y') AS PRICE
|
||||
, (SELECT MIN(DISCOUNT_PRICE) FROM MU_TREATMENT_PROCEDURE_PRICE C
|
||||
LEFT OUTER JOIN HP_CONTENTS_BBS_PROCEDURE B ON A.POST_NO = B.POST_NO AND A.CATEGORY_DIV_CD = B.CATEGORY_DIV_CD AND A.CATEGORY_NO = B.CATEGORY_NO AND B.USE_YN = 'Y'
|
||||
WHERE B.MU_TREATMENT_PROCEDURE_ID = C.MU_TREATMENT_PROCEDURE_ID AND C.USE_YN = 'Y') AS DISCOUNT_PRICE
|
||||
FROM HP_CONTENTS_BBS A
|
||||
LEFT OUTER JOIN HP_CATEGORY C ON A.CATEGORY_NO = C.CATEGORY_NO AND A.CATEGORY_DIV_CD = C.CATEGORY_DIV_CD
|
||||
LEFT OUTER JOIN HP_ATTACH_FILE D ON A.THUMBNAIL_ATTACHFILE_ID = D.ATTACHFILE_ID
|
||||
LEFT OUTER JOIN HP_ATTACH_FILE E ON A.CONTENTS_ATTACHFILE_ID = E.ATTACHFILE_ID
|
||||
WHERE A.USE_YN = 'Y'
|
||||
AND A.CATEGORY_DIV_CD = #{CATEGORY_DIV_CD}
|
||||
AND A.CATEGORY_NO = #{CATEGORY_NO}
|
||||
AND A.POST_NO = #{POST_NO}
|
||||
</select>
|
||||
|
||||
<!-- 예약 저장 -->
|
||||
<insert id="insertReservation" parameterType="hashmap">
|
||||
<selectKey resultType="string" keyProperty="id" order="BEFORE">
|
||||
SELECT CONCAT(#{muReserveId},LPAD((SELECT NEXTVAL(MU_RESERVE_SEQ)), 11, 0))
|
||||
</selectKey>
|
||||
INSERT INTO MU_RESERVE(
|
||||
MU_RESERVE_ID
|
||||
,USER_NAME
|
||||
,PHONE_NUMBER
|
||||
,RESERVE_DATE
|
||||
,RESERVE_TIME
|
||||
,MU_TREATMENT_ID
|
||||
,TREATMENT_NAME
|
||||
,MU_TREATMENT_PROCEDURE_ID
|
||||
,TREATMENT_PROCEDURE_NAME
|
||||
,ETC
|
||||
,STATUS
|
||||
,STATUS2
|
||||
,WRITE_DATE
|
||||
,WRITE_TIME
|
||||
,CUD_FLAG
|
||||
,USE_YN
|
||||
,REG_ID
|
||||
,REG_DATE
|
||||
,MOD_ID
|
||||
,MOD_DATE
|
||||
)VALUES(
|
||||
#{id}
|
||||
,#{NAME}
|
||||
,#{PHONE_NUMBER}
|
||||
,#{SELECTED_DATE}
|
||||
,#{TIME}
|
||||
,#{P_TREATMENT_ID}
|
||||
,#{P_TREATMENT_NM}
|
||||
,#{P_PROCEDURE_ID}
|
||||
,#{P_PROCEDURE_NM}
|
||||
,#{ETC,jdbcType=VARCHAR}
|
||||
,'T'
|
||||
,'N'
|
||||
,CURDATE()
|
||||
,CURTIME()
|
||||
,'C'
|
||||
,'Y'
|
||||
,'customer'
|
||||
,NOW()
|
||||
,'customer'
|
||||
,NOW()
|
||||
)
|
||||
</insert>
|
||||
</mapper>
|
||||
@@ -15,6 +15,8 @@
|
||||
<!-- 카테고리 상세 목록 조회 -->
|
||||
<select id="selectListEvent" parameterType="hashmap" resultType="hashmap">
|
||||
SELECT 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
|
||||
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,
|
||||
@@ -26,12 +28,14 @@
|
||||
WHERE A.USE_YN = 'Y'
|
||||
AND A.CATEGORY_DIV_CD = '04'
|
||||
AND A.CATEGORY_NO = #{category_no}
|
||||
ORDER BY A.REG_DATE DESC
|
||||
ORDER BY ORD_NO DESC
|
||||
</select>
|
||||
|
||||
<!-- 이벤트안내 상세 조회 -->
|
||||
<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,
|
||||
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
|
||||
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,
|
||||
|
||||
64
src/main/resources/mappers/WebReviewSqlMap.xml
Normal file
@@ -0,0 +1,64 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="WebReview">
|
||||
|
||||
<select id="selectTotalProcedureReviewCount" parameterType="hashmap" resultType="hashmap">
|
||||
SELECT COUNT(*) AS "totalCount"
|
||||
FROM MU_PROCEDURE_REVIEW MPR
|
||||
WHERE MPR.USE_YN = 'Y'
|
||||
AND MPR.CATEGORY_DIV_CD = #{categoryDivCd}
|
||||
<if test="title != null and title != ''">
|
||||
AND MPR.TITLE LIKE CONCAT('%', TRIM(#{title}), '%')
|
||||
</if>
|
||||
</select>
|
||||
|
||||
<select id="selectListProcedureReview" parameterType="hashmap" resultType="hashmap">
|
||||
SELECT MPR.*
|
||||
FROM (
|
||||
SELECT MPR.*
|
||||
,CAST(@RNUM:=@RNUM + 1 AS CHAR) AS "rowNum"
|
||||
FROM (
|
||||
SELECT MPR.MU_PROCEDURE_REVIEW_ID AS "muProcedureReviewId"
|
||||
,MPR.CATEGORY_DIV_CD AS "categoryDivCd"
|
||||
,MPR.TITLE AS "title"
|
||||
,MPR.CONTENT AS "summary"
|
||||
,MPR.HASHTAG AS "hashtag"
|
||||
,MPR.VIEW_COUNT AS "viewCount"
|
||||
,DATE_FORMAT(MPR.REG_DATE, '%Y-%m-%d') AS "writeDate"
|
||||
FROM MU_PROCEDURE_REVIEW MPR
|
||||
WHERE MPR.USE_YN = 'Y'
|
||||
AND MPR.CATEGORY_DIV_CD = #{categoryDivCd}
|
||||
<if test="title != null and title != ''">
|
||||
AND MPR.TITLE LIKE CONCAT('%', TRIM(#{title}), '%')
|
||||
</if>
|
||||
ORDER BY MPR.REG_DATE DESC
|
||||
LIMIT 18446744073709551615
|
||||
) MPR, (SELECT @RNUM:=0) R
|
||||
WHERE 1 = 1
|
||||
) MPR
|
||||
WHERE 1 = 1
|
||||
LIMIT ${start}, ${limit}
|
||||
</select>
|
||||
|
||||
<select id="selectProcedureReview" parameterType="hashmap" resultType="hashmap">
|
||||
SELECT MPR.MU_PROCEDURE_REVIEW_ID AS "muProcedureReviewId"
|
||||
,MPR.CATEGORY_DIV_CD AS "categoryDivCd"
|
||||
,MPR.TITLE AS "title"
|
||||
,MPR.CONTENT AS "content"
|
||||
,MPR.HASHTAG AS "hashtag"
|
||||
,MPR.VIEW_COUNT AS "viewCount"
|
||||
,DATE_FORMAT(MPR.REG_DATE, '%Y-%m-%d') AS "writeDate"
|
||||
FROM MU_PROCEDURE_REVIEW MPR
|
||||
WHERE MPR.USE_YN = 'Y'
|
||||
AND MPR.MU_PROCEDURE_REVIEW_ID = #{muProcedureReviewId}
|
||||
LIMIT 0, 1
|
||||
</select>
|
||||
|
||||
<update id="updateViewCount" parameterType="hashmap">
|
||||
UPDATE MU_PROCEDURE_REVIEW
|
||||
SET VIEW_COUNT = IFNULL(VIEW_COUNT, 0) + 1
|
||||
WHERE USE_YN = 'Y'
|
||||
AND MU_PROCEDURE_REVIEW_ID = #{muProcedureReviewId}
|
||||
</update>
|
||||
|
||||
</mapper>
|
||||
@@ -25,6 +25,7 @@
|
||||
WHERE A.USE_YN = 'Y'
|
||||
AND A.CATEGORY_DIV_CD = '03'
|
||||
AND A.CATEGORY_NO = #{categoryNo}
|
||||
ORDER BY ORD_NO DESC
|
||||
</select>
|
||||
|
||||
<!-- 카테고리 상세 조회 -->
|
||||
@@ -69,70 +70,4 @@
|
||||
AND A.POST_NO = #{POST_NO}
|
||||
</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>
|
||||
@@ -53,7 +53,7 @@ html { scroll-behavior:smooth; }
|
||||
|
||||
/* 세로형 드롭다운 메뉴 - 타이트한 박스, 보더 제거 */
|
||||
.project_wrap header nav ul.depth1 li ul.depth2 {
|
||||
width: 160px;
|
||||
width: 180px;
|
||||
height: auto;
|
||||
padding: 8px 0;
|
||||
position: absolute;
|
||||
|
||||
@@ -1,435 +1,471 @@
|
||||
/* main_img */
|
||||
.project_wrap .same main .main_img .text_box > div { width:50%; }
|
||||
.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; }
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
|
||||
.fix_area {
|
||||
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%;
|
||||
body {
|
||||
font-family: 'Noto Sans KR', sans-serif;
|
||||
margin: 0;
|
||||
background: #f7f7f9;
|
||||
color: #222;
|
||||
}
|
||||
|
||||
|
||||
.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;
|
||||
#service-header {
|
||||
background: #fff;
|
||||
max-height: 224px;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
border-bottom: 1px solid #ececec;
|
||||
padding: 14px 0 14px 24px;
|
||||
font-size: 0.98em;
|
||||
color: #888;
|
||||
}
|
||||
|
||||
|
||||
.oi-wrap .oi-price {
|
||||
flex: 0 0 35%;
|
||||
max-width: 35%;
|
||||
text-align: right;
|
||||
.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;
|
||||
}
|
||||
|
||||
.original_price {
|
||||
color: #757575;
|
||||
opacity: 0.7;
|
||||
.top-section {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 32px;
|
||||
padding: 32px 32px 0 32px;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.d-block {
|
||||
display: block;
|
||||
.img-box {
|
||||
border-radius: 18px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.discount_price {
|
||||
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;
|
||||
.img-box img {
|
||||
width: 100%;
|
||||
object-fit: cover;
|
||||
border-radius: 18px;
|
||||
}
|
||||
|
||||
.selt_info_wrap .selt {
|
||||
padding-top: 0.3em;
|
||||
padding-right: 8.5em;
|
||||
.info-box {
|
||||
flex: 1 1 300px;
|
||||
min-width: 240px;
|
||||
}
|
||||
|
||||
.total-price-area .total {
|
||||
position: relative;
|
||||
background-color: #e6e6e6;
|
||||
padding: 25px 25px 60px;
|
||||
.info-title {
|
||||
font-size: 1.7em;
|
||||
font-weight: 700;
|
||||
margin-bottom: 6px;
|
||||
color: #222;
|
||||
}
|
||||
|
||||
.info-desc {
|
||||
color: #444;
|
||||
font-size: 1.1em;
|
||||
margin-bottom: 18px;
|
||||
}
|
||||
|
||||
.event-period {
|
||||
font-size: 1.05em;
|
||||
font-weight: 600;
|
||||
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;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
font-size: 1.1em;
|
||||
margin-bottom: 18px;
|
||||
}
|
||||
|
||||
.total-price-area .total .txt_sub {
|
||||
color: #222222;
|
||||
font-size: 2rem;
|
||||
opacity: 1;
|
||||
}
|
||||
.total-price-area .total .right strong {
|
||||
font-size: 22px;
|
||||
font-weight: 600;
|
||||
.total-row .total-label {
|
||||
color: #888;
|
||||
}
|
||||
|
||||
.total-price-area .total-price-txt {
|
||||
font-family: 'Campton', Sans-serif;
|
||||
font-weight: 600;
|
||||
color: #A73439;
|
||||
.total-row .total-price {
|
||||
font-weight: bold;
|
||||
color: #b23c3c;
|
||||
}
|
||||
|
||||
.total-price-area .total .bs-txt {
|
||||
position: absolute;
|
||||
bottom: 17px;
|
||||
right: 25px;
|
||||
display: block;
|
||||
margin-top: 4px;
|
||||
font-size: 12px;
|
||||
color: #999999;
|
||||
letter-spacing: -1px;
|
||||
}
|
||||
|
||||
|
||||
.main_btn {
|
||||
text-align: right;
|
||||
margin: 1rem 0;
|
||||
}
|
||||
|
||||
.main_btn button {
|
||||
width: 180px;
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
|
||||
.fastrack-btn {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
border: 1px solid #a73439;
|
||||
background-color: #a73439;
|
||||
.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;
|
||||
}
|
||||
|
||||
.img-content{
|
||||
background-color: #eee;
|
||||
.reserve-btn:disabled {
|
||||
background: #ddd;
|
||||
color: #888;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.img-area{
|
||||
padding-top: 70px;
|
||||
padding-bottom: 200px;
|
||||
text-align:center;
|
||||
.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 {
|
||||
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%; }
|
||||
.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; }
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.project_wrap .same aside {background: white; width: 30%; top: 12%;}
|
||||
.project_wrap .same aside ul{position: fixed; left: 5%; width: 19%;}
|
||||
.project_wrap .same aside ul li{margin-bottom: 0.5rem; margin-top: 0px;}
|
||||
.project_wrap .same aside .first {padding-top: 1rem; padding-bottom: 1rem;}
|
||||
.project_wrap .same aside .nonactive {border: 1px solid #d8d8d8; background-color: #f9f9fb;}
|
||||
.project_wrap .same aside .active {border: 1px solid #d8d8d8; color: #a73439; background-color: rgba(118, 35, 47, 0); border-left: 2px solid #a73439;}
|
||||
.project_wrap .same aside ul a{padding-left: 10px;}
|
||||
.project_wrap .same main {width: 60%; padding-top: 7%;}
|
||||
.project_wrap .same main ul{padding-top: 2%; width:102%;}
|
||||
.event-card-list > ul { display: block; list-style-type: disc; margin-block-start: 1em; margin-block-end: 1em; padding-inline-start: 40px; unicode-bidi: isolate; }
|
||||
.event-card-list > li { margin-bottom: 70px; opacity: 1;}
|
||||
.event-card-list .event-card { display: block; position: relative; width: 775px; height: 196px; padding-right: 10px; margin-left: auto; overflow: hidden;}
|
||||
.event-card .img_box { position: relative; width: 350px; height: 100%; background-color: black; float: left; overflow: hidden; }
|
||||
.event-card .img_box img { position: absolute; min-width: 100%; min-height: 100%; width: 100%; height: 100%; margin: auto; top: 0; bottom: 0; left: 0; right: 0; opacity: 1; transform: scale(1); transition: .4s ease-out;}
|
||||
.event-card .txt-box { position: relative; padding-top: 115px; width: 343px; height: 100%; float: right;}
|
||||
.event-card .txt-box .tit-txt { position: absolute; left: 0; bottom: 88px;}
|
||||
.txt-box .tit-txt > p { margin: 0; font-size: 22px; font-weight: 500; line-height: 1.3;}
|
||||
.event-card .txt-box > .sub-txt { font-size: 12px;}
|
||||
.one-ellip { position: relative;overflow: hidden; white-space: nowrap; text-overflow: ellipsis; left: 0%; width: 100%;-webkit-transition: left 3s, width 3s; -moz-transition: left 3s, width 3s; transition: left 3s, width 3s;}
|
||||
.event-card .txt-box .ab_cont { padding-top: 10px;}
|
||||
.ab_cont .cost { font-size: 13px; font-weight: 400; color: #7D7971;}
|
||||
del { text-decoration: line-through;}
|
||||
.ab_cont .discount { display: block; font-size: 1rem;}
|
||||
.ab_cont .discount .txt_num { font-size: 1.6em; font-weight: 600; color: #9F2A2A;}
|
||||
.event-card .txt-box .tit-txt:After { content: ''; position: absolute; top: -49px; left: 0; width: 18px; height: 35px; background: center / contain url(https://www.toxnfill2.com/imges/ico-toxnfill-g.png) no-repeat;}
|
||||
.event-card-list .event-card:after { content: ''; position: absolute; bottom: 9px; right: 0; width: 58px; height: 15px; background: center / contain url(https://www.toxnfill2.com/imges/long-arrow-right-g.png) no-repeat;}
|
||||
.add-ticket-btn {
|
||||
font-size: 1.2rem;
|
||||
font-weight: 400;
|
||||
letter-spacing: -0.03em;
|
||||
padding: .35rem 1rem;
|
||||
border: 1px solid #ced4da;
|
||||
border-radius: 50em;
|
||||
transition: 0.2s;
|
||||
background:white;
|
||||
/* 전체 기본 스타일 */
|
||||
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;
|
||||
}
|
||||
.right { float: right;}
|
||||
.left { float: left;}
|
||||
.card_otxt {
|
||||
position: relative;
|
||||
display: block;
|
||||
border-radius: 1rem;
|
||||
padding: 1rem;
|
||||
}
|
||||
.border {
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
.__card_otxt {
|
||||
height: 95px;
|
||||
}
|
||||
.row>.col2 {
|
||||
width: 50%;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
.row.row_padding>.col2, .row.row_padding>.col3, .row.row_padding>.col4, .row.row_padding>.col5 {
|
||||
padding-right: 1rem;
|
||||
padding-left: 1rem;
|
||||
}
|
||||
.row.row_padding {
|
||||
margin-left: -1rem;
|
||||
margin-right: -1rem;
|
||||
|
||||
/* 메인 컨테이너 */
|
||||
.container {
|
||||
max-width: 1280px;
|
||||
width: 100%;
|
||||
margin: 0 auto;
|
||||
min-height: calc(100vh - 300px);
|
||||
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;
|
||||
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;
|
||||
right: 1rem;
|
||||
top: 3.4rem;
|
||||
width: 8.5em;
|
||||
text-align: right;
|
||||
top: 12px;
|
||||
right: 12px;
|
||||
background: rgba(107, 114, 128, 0.9);
|
||||
color: #fff;
|
||||
padding: 4px 12px;
|
||||
border-radius: 20px;
|
||||
font-size: 0.8rem;
|
||||
font-weight: 600;
|
||||
z-index: 2;
|
||||
}
|
||||
.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;
|
||||
word-break: keep-all;
|
||||
}
|
||||
.mb3{margin-bottom: 3rem;}
|
||||
.mt70{margin-top: 70%;}
|
||||
|
||||
|
||||
/* 반응형 - 모바일 */
|
||||
@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; }
|
||||
.project_wrap .same main {width: 100%;}
|
||||
/* 로딩 및 에러 메시지 */
|
||||
.loading {
|
||||
text-align: center;
|
||||
padding: 2rem;
|
||||
color: #6b7280;
|
||||
font-size: 0.9375rem;
|
||||
}
|
||||
|
||||
.error-message {
|
||||
text-align: center;
|
||||
padding: 2rem;
|
||||
color: #dc2626;
|
||||
font-size: 0.9375rem;
|
||||
}
|
||||
|
||||
/* 레이어 팝업 */
|
||||
.popup-overlay {
|
||||
display: none;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
z-index: 9999;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.popup-overlay.active {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.popup-content {
|
||||
background: white;
|
||||
border-radius: 16px;
|
||||
padding: 2rem 2.5rem;
|
||||
text-align: center;
|
||||
box-shadow: 0 8px 40px rgba(0, 0, 0, 0.2);
|
||||
max-width: 400px;
|
||||
width: 90%;
|
||||
animation: popupIn 0.25s ease-out;
|
||||
}
|
||||
|
||||
@keyframes popupIn {
|
||||
from {
|
||||
transform: scale(0.9);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
to {
|
||||
transform: scale(1);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.popup-icon {
|
||||
font-size: 3rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.popup-title {
|
||||
font-size: 1.25rem;
|
||||
font-weight: 700;
|
||||
color: #1a1a1a;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.popup-message {
|
||||
font-size: 0.95rem;
|
||||
color: #6b7280;
|
||||
margin-bottom: 1.5rem;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.popup-close-btn {
|
||||
background: #C60B24;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
padding: 0.75rem 2rem;
|
||||
font-size: 1rem;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: background 0.2s;
|
||||
}
|
||||
|
||||
.popup-close-btn:hover {
|
||||
background: #a5091e;
|
||||
}
|
||||
|
||||
/* 스크롤바 커스터마이징 */
|
||||
.event-list::-webkit-scrollbar,
|
||||
.sidebar::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
|
||||
.event-list::-webkit-scrollbar-track,
|
||||
.sidebar::-webkit-scrollbar-track {
|
||||
background: #f8fafc;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.event-list::-webkit-scrollbar-thumb,
|
||||
.sidebar::-webkit-scrollbar-thumb {
|
||||
background: #cbd5e1;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.event-list::-webkit-scrollbar-thumb:hover,
|
||||
.sidebar::-webkit-scrollbar-thumb:hover {
|
||||
background: #C60B24;
|
||||
}
|
||||
|
||||
/* 반응형 디자인 - 태블릿 */
|
||||
@media (max-width: 1024px) {
|
||||
.container {
|
||||
padding: 1rem;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.content-wrapper {
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
width: 220px;
|
||||
min-width: 200px;
|
||||
}
|
||||
|
||||
.event-img {
|
||||
width: 220px;
|
||||
min-width: 220px;
|
||||
}
|
||||
|
||||
.event-img img {
|
||||
height: 140px;
|
||||
}
|
||||
|
||||
.header {
|
||||
padding: 1.25rem 1.5rem;
|
||||
}
|
||||
|
||||
.page-title {
|
||||
font-size: clamp(1.375rem, 2.8vw, 1.75rem);
|
||||
}
|
||||
}
|
||||
|
||||
/* 반응형 디자인 - 모바일 */
|
||||
@media (max-width: 768px) {
|
||||
.container {
|
||||
flex-direction: column;
|
||||
padding: 1rem;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.content-wrapper {
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
width: 100%;
|
||||
position: static;
|
||||
max-height: none;
|
||||
order: 1;
|
||||
}
|
||||
|
||||
.category-list {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
|
||||
gap: 0.5rem;
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.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,248 @@
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
height: 100vh;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: 'Pretendard', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
||||
background: #f8f9fa;
|
||||
color: #1a1a1a;
|
||||
overflow-x: hidden;
|
||||
font-size: 16px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 900px;
|
||||
width: 100%;
|
||||
margin: 0 auto;
|
||||
min-height: calc(100vh - 300px);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1.5rem;
|
||||
}
|
||||
|
||||
.breadcrumb {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
font-size: 0.875rem;
|
||||
color: #9ca3af;
|
||||
padding: 0.5rem 0;
|
||||
}
|
||||
|
||||
.breadcrumb a {
|
||||
color: #6b7280;
|
||||
text-decoration: none;
|
||||
transition: color 0.2s;
|
||||
}
|
||||
|
||||
.breadcrumb a:hover {
|
||||
color: #C60B24;
|
||||
}
|
||||
|
||||
.review-article {
|
||||
background: white;
|
||||
border-radius: 16px;
|
||||
box-shadow: 0 2px 16px rgba(0, 0, 0, 0.06);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.review-header {
|
||||
padding: 2rem 2rem 1.5rem;
|
||||
border-bottom: 1px solid #f1f5f9;
|
||||
}
|
||||
|
||||
.review-title {
|
||||
font-size: clamp(1.375rem, 3vw, 1.75rem);
|
||||
font-weight: 700;
|
||||
color: #1a1a1a;
|
||||
margin: 0 0 1rem;
|
||||
letter-spacing: -0.025em;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.review-meta {
|
||||
display: flex;
|
||||
gap: 1.5rem;
|
||||
font-size: 0.875rem;
|
||||
color: #9ca3af;
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.review-tags {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.review-tag {
|
||||
display: inline-block;
|
||||
padding: 0.25rem 0.75rem;
|
||||
background: rgba(198, 11, 36, 0.08);
|
||||
color: #C60B24;
|
||||
border-radius: 20px;
|
||||
font-size: 0.8125rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.review-content {
|
||||
padding: 2rem;
|
||||
min-height: 300px;
|
||||
}
|
||||
|
||||
.review-content img {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
border-radius: 8px;
|
||||
margin: 0.5rem 0;
|
||||
}
|
||||
|
||||
.review-content p {
|
||||
margin: 0 0 0.75rem;
|
||||
line-height: 1.8;
|
||||
}
|
||||
|
||||
.review-content h1,
|
||||
.review-content h2,
|
||||
.review-content h3 {
|
||||
margin: 1.5rem 0 0.75rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.review-content blockquote {
|
||||
border-left: 4px solid #C60B24;
|
||||
padding: 0.75rem 1rem;
|
||||
margin: 1rem 0;
|
||||
background: #fafafa;
|
||||
border-radius: 0 8px 8px 0;
|
||||
}
|
||||
|
||||
.review-content ul,
|
||||
.review-content ol {
|
||||
padding-left: 1.5rem;
|
||||
margin: 0.5rem 0;
|
||||
}
|
||||
|
||||
.review-content li {
|
||||
margin: 0.25rem 0;
|
||||
list-style: inherit;
|
||||
}
|
||||
|
||||
.ql-editor .ql-align-center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.ql-editor .ql-align-right {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.ql-editor .ql-align-justify {
|
||||
text-align: justify;
|
||||
}
|
||||
|
||||
.ql-editor .ql-indent-1 {
|
||||
padding-left: 3em;
|
||||
}
|
||||
|
||||
.ql-editor .ql-indent-2 {
|
||||
padding-left: 6em;
|
||||
}
|
||||
|
||||
.ql-editor .ql-indent-3 {
|
||||
padding-left: 9em;
|
||||
}
|
||||
|
||||
.ql-editor .ql-size-small {
|
||||
font-size: 0.75em;
|
||||
}
|
||||
|
||||
.ql-editor .ql-size-large {
|
||||
font-size: 1.5em;
|
||||
}
|
||||
|
||||
.ql-editor .ql-size-huge {
|
||||
font-size: 2.5em;
|
||||
}
|
||||
|
||||
.ql-editor .ql-font-serif {
|
||||
font-family: Georgia, 'Times New Roman', serif;
|
||||
}
|
||||
|
||||
.ql-editor .ql-font-monospace {
|
||||
font-family: 'Monaco', 'Courier New', monospace;
|
||||
}
|
||||
|
||||
.btn-area {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding-bottom: 2rem;
|
||||
}
|
||||
|
||||
.btn-list {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
padding: 0.75rem 2.5rem;
|
||||
background: white;
|
||||
color: #1a1a1a;
|
||||
border: 1px solid #e5e7eb;
|
||||
border-radius: 10px;
|
||||
font-size: 0.9375rem;
|
||||
font-weight: 600;
|
||||
text-decoration: none;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.btn-list:hover {
|
||||
border-color: #C60B24;
|
||||
color: #C60B24;
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
.loading {
|
||||
text-align: center;
|
||||
padding: 3rem;
|
||||
color: #6b7280;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.container {
|
||||
padding: 1rem;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.review-header {
|
||||
padding: 1.5rem;
|
||||
}
|
||||
|
||||
.review-content {
|
||||
padding: 1.5rem;
|
||||
}
|
||||
|
||||
.review-title {
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
|
||||
.review-meta {
|
||||
flex-direction: column;
|
||||
gap: 0.25rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.container {
|
||||
padding: 0.75rem;
|
||||
}
|
||||
|
||||
.review-header {
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.review-content {
|
||||
padding: 1rem;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,399 @@
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
height: 100vh;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: 'Pretendard', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
||||
background: #f8f9fa;
|
||||
color: #1a1a1a;
|
||||
overflow-x: hidden;
|
||||
font-size: 16px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 1280px;
|
||||
width: 100%;
|
||||
margin: 0 auto;
|
||||
min-height: calc(100vh - 300px);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1.5rem;
|
||||
}
|
||||
|
||||
.header {
|
||||
background: white;
|
||||
border-radius: 16px;
|
||||
box-shadow: 0 2px 16px rgba(0, 0, 0, 0.06);
|
||||
padding: 1.5rem 2rem;
|
||||
border-bottom: 3px solid #C60B24;
|
||||
}
|
||||
|
||||
.page-title {
|
||||
font-size: clamp(1.5rem, 3vw, 1.875rem);
|
||||
font-weight: 700;
|
||||
color: #1a1a1a;
|
||||
margin: 0;
|
||||
letter-spacing: -0.025em;
|
||||
}
|
||||
|
||||
.page-subtitle {
|
||||
font-size: 0.95rem;
|
||||
color: #6b7280;
|
||||
margin: 0.25rem 0 0;
|
||||
}
|
||||
|
||||
.search-area {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.search-box {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.search-box input {
|
||||
width: 280px;
|
||||
padding: 0.625rem 1rem;
|
||||
border: 1px solid #e5e7eb;
|
||||
border-radius: 10px;
|
||||
font-size: 0.9375rem;
|
||||
outline: none;
|
||||
transition: border-color 0.2s;
|
||||
}
|
||||
|
||||
.search-box input:focus {
|
||||
border-color: #C60B24;
|
||||
}
|
||||
|
||||
.search-btn {
|
||||
padding: 0.625rem 1.25rem;
|
||||
background: #C60B24;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 10px;
|
||||
font-size: 0.9375rem;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: background 0.2s;
|
||||
}
|
||||
|
||||
.search-btn:hover {
|
||||
background: #a5091e;
|
||||
}
|
||||
|
||||
.review-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(360px, 1fr));
|
||||
gap: 1.5rem;
|
||||
}
|
||||
|
||||
.review-card {
|
||||
background: white;
|
||||
border-radius: 16px;
|
||||
box-shadow: 0 2px 16px rgba(0, 0, 0, 0.06);
|
||||
overflow: hidden;
|
||||
transition: all 0.3s ease;
|
||||
border: 1px solid #f1f5f9;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.review-card:hover {
|
||||
transform: translateY(-4px);
|
||||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.12);
|
||||
border-color: #C60B24;
|
||||
}
|
||||
|
||||
/* ===== 이미지 슬라이더 ===== */
|
||||
.review-slider {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
aspect-ratio: 4 / 3;
|
||||
overflow: hidden;
|
||||
background: #f1f5f9;
|
||||
}
|
||||
|
||||
.review-slider-track {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
transition: transform 0.4s cubic-bezier(0.25, 0.46, 0.45, 0.94);
|
||||
}
|
||||
|
||||
.review-slider-track img {
|
||||
min-width: 100%;
|
||||
max-width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.slider-arrow {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
background: rgba(0, 0, 0, 0.45);
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 50%;
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
opacity: 0;
|
||||
transition: opacity 0.25s;
|
||||
z-index: 2;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.review-slider:hover .slider-arrow {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.slider-arrow.prev {
|
||||
left: 8px;
|
||||
}
|
||||
|
||||
.slider-arrow.next {
|
||||
right: 8px;
|
||||
}
|
||||
|
||||
.slider-arrow:hover {
|
||||
background: rgba(0, 0, 0, 0.7);
|
||||
}
|
||||
|
||||
.slider-dots {
|
||||
position: absolute;
|
||||
bottom: 8px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
display: flex;
|
||||
gap: 5px;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.slider-dot {
|
||||
width: 7px;
|
||||
height: 7px;
|
||||
border-radius: 50%;
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
padding: 0;
|
||||
transition: all 0.25s;
|
||||
}
|
||||
|
||||
.slider-dot.active {
|
||||
background: white;
|
||||
transform: scale(1.3);
|
||||
}
|
||||
|
||||
.slider-count {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
background: rgba(0, 0, 0, 0.55);
|
||||
color: white;
|
||||
font-size: 0.75rem;
|
||||
padding: 2px 8px;
|
||||
border-radius: 12px;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.review-no-image {
|
||||
width: 100%;
|
||||
aspect-ratio: 4 / 3;
|
||||
background: linear-gradient(135deg, #f1f5f9 0%, #e2e8f0 100%);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 2.5rem;
|
||||
color: #cbd5e1;
|
||||
}
|
||||
|
||||
.review-card-body {
|
||||
padding: 1.25rem 1.5rem 1.5rem;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.review-card-title {
|
||||
font-size: 1.0625rem;
|
||||
font-weight: 700;
|
||||
color: #1a1a1a;
|
||||
margin-bottom: 0.5rem;
|
||||
letter-spacing: -0.025em;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.review-card-summary {
|
||||
color: #6b7280;
|
||||
font-size: 0.8125rem;
|
||||
line-height: 1.6;
|
||||
flex: 1;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.review-card-tags {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.375rem;
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.review-tag {
|
||||
display: inline-block;
|
||||
padding: 0.2rem 0.5rem;
|
||||
background: rgba(198, 11, 36, 0.08);
|
||||
color: #C60B24;
|
||||
border-radius: 20px;
|
||||
font-size: 0.6875rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.review-card-footer {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
font-size: 0.8125rem;
|
||||
color: #9ca3af;
|
||||
}
|
||||
|
||||
.review-card-footer .views {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.25rem;
|
||||
}
|
||||
|
||||
.pagination-area {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 0.375rem;
|
||||
padding: 1rem 0 2rem;
|
||||
}
|
||||
|
||||
.page-btn {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: 1px solid #e5e7eb;
|
||||
background: white;
|
||||
border-radius: 8px;
|
||||
font-size: 0.875rem;
|
||||
color: #6b7280;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.page-btn:hover {
|
||||
border-color: #C60B24;
|
||||
color: #C60B24;
|
||||
}
|
||||
|
||||
.page-btn.active {
|
||||
background: #C60B24;
|
||||
color: white;
|
||||
border-color: #C60B24;
|
||||
}
|
||||
|
||||
.page-btn.disabled {
|
||||
opacity: 0.4;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.loading {
|
||||
text-align: center;
|
||||
padding: 3rem;
|
||||
color: #6b7280;
|
||||
font-size: 0.9375rem;
|
||||
grid-column: 1 / -1;
|
||||
}
|
||||
|
||||
.empty-state {
|
||||
text-align: center;
|
||||
padding: 4rem 2rem;
|
||||
grid-column: 1 / -1;
|
||||
}
|
||||
|
||||
.empty-state .icon {
|
||||
font-size: 3rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.empty-state .message {
|
||||
font-size: 1.125rem;
|
||||
color: #6b7280;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.container {
|
||||
padding: 1rem;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.header {
|
||||
padding: 1rem 1.5rem;
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
.page-title {
|
||||
font-size: clamp(1.25rem, 2.5vw, 1.5rem);
|
||||
}
|
||||
|
||||
.review-grid {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.search-area {
|
||||
justify-content: stretch;
|
||||
}
|
||||
|
||||
.search-box {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.search-box input {
|
||||
flex: 1;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.slider-arrow {
|
||||
opacity: 0.7;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.container {
|
||||
padding: 0.75rem;
|
||||
}
|
||||
|
||||
.header {
|
||||
padding: 0.875rem 1rem;
|
||||
}
|
||||
|
||||
.review-card-body {
|
||||
padding: 1rem;
|
||||
}
|
||||
}
|
||||
BIN
src/main/resources/static/image/equip/20251014/써마지.jpg
Normal file
|
After Width: | Height: | Size: 99 KiB |
BIN
src/main/resources/static/image/equip/20251014/울쎄라.jpg
Normal file
|
After Width: | Height: | Size: 92 KiB |
BIN
src/main/resources/static/image/equip/20251014/줄기세포.jpg
Normal file
|
After Width: | Height: | Size: 89 KiB |
BIN
src/main/resources/static/image/equip/20251014/튠페이스.jpg
Normal file
|
After Width: | Height: | Size: 104 KiB |
BIN
src/main/resources/static/image/equip/20251014/티타늄.jpg
Normal file
|
After Width: | Height: | Size: 100 KiB |
BIN
src/main/resources/static/image/equip/20260313/써마지FLX.jpg
Normal file
|
After Width: | Height: | Size: 115 KiB |
BIN
src/main/resources/static/image/equip/20260313/온다리프팅(Face).jpg
Normal file
|
After Width: | Height: | Size: 163 KiB |
BIN
src/main/resources/static/image/equip/20260313/울쎄라.jpg
Normal file
|
After Width: | Height: | Size: 104 KiB |
BIN
src/main/resources/static/image/equip/20260313/튠페이스.jpg
Normal file
|
After Width: | Height: | Size: 124 KiB |
BIN
src/main/resources/static/image/equip/20260313/티타늄리프팅(Face).jpg
Normal file
|
After Width: | Height: | Size: 124 KiB |
BIN
src/main/resources/static/image/equip/온다리프팅.jpg
Normal file
|
After Width: | Height: | Size: 44 KiB |
BIN
src/main/resources/static/image/quick_menu/event.png
Normal file
|
After Width: | Height: | Size: 6.8 KiB |
BIN
src/main/resources/static/image/quick_menu/review.png
Normal file
|
After Width: | Height: | Size: 8.1 KiB |
BIN
src/main/resources/static/image/signature/20251024/레이저리프팅.jpg
Normal file
|
After Width: | Height: | Size: 255 KiB |
|
After Width: | Height: | Size: 250 KiB |
BIN
src/main/resources/static/image/signature/20251024/스컬트라.jpg
Normal file
|
After Width: | Height: | Size: 234 KiB |
BIN
src/main/resources/static/image/signature/20251024/스킨부스터.jpg
Normal file
|
After Width: | Height: | Size: 271 KiB |
BIN
src/main/resources/static/image/signature/20251024/필러.jpg
Normal file
|
After Width: | Height: | Size: 221 KiB |
@@ -7,7 +7,7 @@ function fn_init() {
|
||||
//인스타그램 리스트
|
||||
fn_selectListWebInstagramJson();
|
||||
|
||||
//상단, 하단 배너
|
||||
//상단, 하단 배너
|
||||
fn_selectListWebMainBannerTypeAJson();
|
||||
fn_selectListWebMainBannerTypeBJson();
|
||||
}
|
||||
@@ -47,21 +47,21 @@ function hideBackgroundMask() {
|
||||
************************************************/
|
||||
const cont1Urls = [
|
||||
'https://petit.madeu.co.kr/webservice/selectServiceIntro.do?categoryNo=4' // 첫 번째 슬라이드 URL
|
||||
,'https://petit.madeu.co.kr/webservice/selectServiceIntro.do?categoryNo=1' // 두 번째 슬라이드 URL
|
||||
,'https://petit.madeu.co.kr/webservice/selectServiceIntro.do?categoryNo=5' // 세 번째 슬라이드 URL
|
||||
,'https://petit.madeu.co.kr/index' // 네 번째 슬라이드 URL
|
||||
,'https://petit.madeu.co.kr/webservice/selectServiceIntro.do?categoryNo=1' // 다섯 번째 슬라이드 URL
|
||||
, 'https://petit.madeu.co.kr/webservice/selectServiceIntro.do?categoryNo=1' // 두 번째 슬라이드 URL
|
||||
, 'https://petit.madeu.co.kr/webservice/selectServiceIntro.do?categoryNo=5' // 세 번째 슬라이드 URL
|
||||
, 'https://petit.madeu.co.kr/index' // 네 번째 슬라이드 URL
|
||||
, 'https://petit.madeu.co.kr/webservice/selectServiceIntro.do?categoryNo=1' // 다섯 번째 슬라이드 URL
|
||||
// 필요시 추가
|
||||
];
|
||||
|
||||
const bullet1 = ['레이저리프팅','보톡스','스킨부스터','제모', '필러']
|
||||
const bullet1 = ['레이저리프팅', '쉬다주사(Face)', '스컬트라', '스킨부스터', '필러']
|
||||
|
||||
const useCont1Loop = bullet1.length > 5; // slidesPerView(1.3)보다 많을 때만 loop
|
||||
const cont1Swiper = new Swiper('.cont1_swiper', {
|
||||
loop: useCont1Loop,
|
||||
slidesPerView: 'auto',
|
||||
spaceBetween: 10,
|
||||
autoplay : {
|
||||
autoplay: {
|
||||
disableOnInteraction: false,
|
||||
},
|
||||
pagination: {
|
||||
@@ -73,22 +73,22 @@ const cont1Swiper = new Swiper('.cont1_swiper', {
|
||||
},
|
||||
on: {
|
||||
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.setAttribute('data-url', cont1Urls[idx] || cont1Urls[0]);
|
||||
slide.addEventListener('click', function() {
|
||||
slide.addEventListener('click', function () {
|
||||
const url = slide.getAttribute('data-url');
|
||||
if(url) window.open(url, '_blank');
|
||||
if (url) window.open(url, '_blank');
|
||||
});
|
||||
});
|
||||
},
|
||||
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.setAttribute('data-url', cont1Urls[idx] || cont1Urls[0]);
|
||||
slide.onclick = function() {
|
||||
slide.onclick = function () {
|
||||
const url = slide.getAttribute('data-url');
|
||||
if(url) window.open(url, '_blank');
|
||||
if (url) window.open(url, '_blank');
|
||||
};
|
||||
});
|
||||
}
|
||||
@@ -99,21 +99,21 @@ const cont1Swiper = new Swiper('.cont1_swiper', {
|
||||
* content2 스와이퍼
|
||||
************************************************/
|
||||
const cont2Urls = [
|
||||
'https://petit.madeu.co.kr/webservice/selectServiceIntro.do?categoryNo=4' // 첫 번째 슬라이드 URL
|
||||
,'https://petit.madeu.co.kr/webservice/selectServiceIntro.do?categoryNo=4' // 두 번째 슬라이드 URL
|
||||
,'https://petit.madeu.co.kr/webservice/selectServiceIntro.do?categoryNo=4' // 세 번째 슬라이드 URL
|
||||
,'https://petit.madeu.co.kr/webservice/selectServiceIntro.do?categoryNo=4' // 네 번째 슬라이드 URL
|
||||
,'https://petit.madeu.co.kr/webservice/selectServiceIntro.do?categoryNo=4' // 다섯 번째 슬라이드 URL
|
||||
'https://petit.madeu.co.kr/webservice/selectServiceDetailIntro.do?categoryDivCd=03&categoryNo=4&postNo=8' // 첫 번째 슬라이드 URL
|
||||
, 'https://petit.madeu.co.kr/webservice/selectServiceDetailIntro.do?categoryDivCd=03&categoryNo=4&postNo=2' // 두 번째 슬라이드 URL
|
||||
, 'https://petit.madeu.co.kr/webservice/selectServiceDetailIntro.do?categoryDivCd=03&categoryNo=4&postNo=10' // 세 번째 슬라이드 URL
|
||||
, 'https://petit.madeu.co.kr/webservice/selectServiceDetailIntro.do?categoryDivCd=03&categoryNo=4&postNo=3' // 네 번째 슬라이드 URL
|
||||
, 'https://petit.madeu.co.kr/webservice/selectServiceDetailIntro.do?categoryDivCd=03&categoryNo=4&postNo=4' // 다섯 번째 슬라이드 URL
|
||||
];
|
||||
|
||||
const bullet2 = ['써마지','울세라','줄기세포', '튠페이스', '티타늄리프팅']
|
||||
const bullet2 = ['써마지FLX', '울쎄라', '온다리프팅', '티타늄리프팅', '튠페이스']
|
||||
|
||||
const useCont2Loop = bullet2.length > 5; // slidesPerView(1.3)보다 많을 때만 loop
|
||||
const cont2Swiper = new Swiper('.cont2_swiper', {
|
||||
loop: useCont2Loop,
|
||||
slidesPerView: 'auto',
|
||||
spaceBetween: 10,
|
||||
autoplay : {
|
||||
autoplay: {
|
||||
disableOnInteraction: false,
|
||||
},
|
||||
pagination: {
|
||||
@@ -125,22 +125,22 @@ const cont2Swiper = new Swiper('.cont2_swiper', {
|
||||
},
|
||||
on: {
|
||||
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.setAttribute('data-url', cont2Urls[idx] || cont2Urls[0]);
|
||||
slide.addEventListener('click', function() {
|
||||
slide.addEventListener('click', function () {
|
||||
const url = slide.getAttribute('data-url');
|
||||
if(url) window.open(url, '_blank');
|
||||
if (url) window.open(url, '_blank');
|
||||
});
|
||||
});
|
||||
},
|
||||
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.setAttribute('data-url', cont2Urls[idx] || cont2Urls[0]);
|
||||
slide.onclick = function() {
|
||||
slide.onclick = function () {
|
||||
const url = slide.getAttribute('data-url');
|
||||
if(url) window.open(url, '_blank');
|
||||
if (url) window.open(url, '_blank');
|
||||
};
|
||||
});
|
||||
}
|
||||
@@ -150,7 +150,7 @@ const cont2Swiper = new Swiper('.cont2_swiper', {
|
||||
/****************************************************************************
|
||||
* 팝업 리스트 조회 (마스킹 기능 추가)
|
||||
****************************************************************************/
|
||||
function fn_selectListWebPopupJson(){
|
||||
function fn_selectListWebPopupJson() {
|
||||
let formData = new FormData();
|
||||
|
||||
$.ajax({
|
||||
@@ -161,8 +161,8 @@ function fn_selectListWebPopupJson(){
|
||||
contentType: false,
|
||||
type: 'POST',
|
||||
async: true,
|
||||
success: function(data){
|
||||
if(data.msgCode=='0'){
|
||||
success: function (data) {
|
||||
if (data.msgCode == '0') {
|
||||
//쿠기값 확인
|
||||
let cookiedata = document.cookie;
|
||||
if (cookiedata.indexOf("popup=done") < 0) {
|
||||
@@ -186,9 +186,9 @@ function fn_selectListWebPopupJson(){
|
||||
|
||||
// 탭 콘텐츠 생성
|
||||
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 += '<img src="' + CDN_URL + imgPath + '" alt="event_con' + (i+1) + '" />';
|
||||
contentHTML += '<img src="' + CDN_URL + imgPath + '" alt="event_con' + (i + 1) + '" />';
|
||||
contentHTML += '</a>';
|
||||
contentHTML += '</div>';
|
||||
popupContentList.append(contentHTML);
|
||||
@@ -196,7 +196,7 @@ function fn_selectListWebPopupJson(){
|
||||
// 탭 리스트 생성 (data-toggle 제거하고 클릭 이벤트 직접 처리)
|
||||
let tabHTML = '';
|
||||
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 += '</a>';
|
||||
tabHTML += '</li>';
|
||||
@@ -207,27 +207,27 @@ function fn_selectListWebPopupJson(){
|
||||
setupTabEvents();
|
||||
setupPopupCloseEvents();
|
||||
}
|
||||
}else{
|
||||
} else {
|
||||
$('.popup').removeClass('open');
|
||||
hideBackgroundMask(); // 추가
|
||||
}
|
||||
}else if('-2' == data.msgCode){
|
||||
modalEvent.danger("로그인 오류", data.msgDesc, function(){
|
||||
} else if ('-2' == data.msgCode) {
|
||||
modalEvent.danger("로그인 오류", data.msgDesc, function () {
|
||||
fn_leftFormAction('/weblogin/logout.do');
|
||||
});
|
||||
}else{
|
||||
} else {
|
||||
modalEvent.danger("조회 오류", data.msgDesc);
|
||||
}
|
||||
|
||||
},
|
||||
error : function(xhr, status, error) {
|
||||
error: function (xhr, status, error) {
|
||||
modalEvent.danger("조회 오류", "조회 중 오류가 발생하였습니다. 잠시후 다시시도하십시오.");
|
||||
},
|
||||
beforeSend:function(){
|
||||
beforeSend: function () {
|
||||
// 로딩열기
|
||||
$(".loading-image-layer").show();
|
||||
},
|
||||
complete:function(){
|
||||
complete: function () {
|
||||
// 로딩닫기
|
||||
$(".loading-image-layer").hide();
|
||||
}
|
||||
@@ -236,7 +236,7 @@ function fn_selectListWebPopupJson(){
|
||||
|
||||
// 탭 이벤트 설정 함수 추가
|
||||
function setupTabEvents() {
|
||||
$('#popupTabList a[role="tab"]').off('click').on('click', function(e) {
|
||||
$('#popupTabList a[role="tab"]').off('click').on('click', function (e) {
|
||||
e.preventDefault();
|
||||
|
||||
const targetId = $(this).data('target');
|
||||
@@ -290,7 +290,7 @@ function fn_addBrAfterFirstWord(input) {
|
||||
function setCookie(value, expiredays) {
|
||||
let todayDate = new Date();
|
||||
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');
|
||||
|
||||
// *** 배경 마스킹 제거 추가 ***
|
||||
@@ -300,7 +300,7 @@ function setCookie(value, expiredays) {
|
||||
/****************************************************************************
|
||||
* 메인 배너 리스트 조회
|
||||
****************************************************************************/
|
||||
function fn_selectListWebMainBannerTypeAJson(){
|
||||
function fn_selectListWebMainBannerTypeAJson() {
|
||||
let formData = new FormData();
|
||||
formData.append('bannerType', 'PT');
|
||||
|
||||
@@ -312,8 +312,8 @@ function fn_selectListWebMainBannerTypeAJson(){
|
||||
contentType: false,
|
||||
type: 'POST',
|
||||
async: true,
|
||||
success: function(data){
|
||||
if(data.msgCode=='0'){
|
||||
success: function (data) {
|
||||
if (data.msgCode == '0') {
|
||||
let totalCount = data.rows.length;
|
||||
if (0 < totalCount) {
|
||||
let listHTML = '';
|
||||
@@ -326,8 +326,8 @@ function fn_selectListWebMainBannerTypeAJson(){
|
||||
// 이미지와 링크를 a 태그로 감싸기 (url 파라미터 사용)
|
||||
listHTML += '<div class="swiper-slide" style="background:' + backgroundColor + ';" aria-label="' + currentAriaLabel + '">';
|
||||
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="mb" src="' + CDN_URL + data.rows[i].mobileFilePath + '" 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 += ' </a>';
|
||||
listHTML += '</div>';
|
||||
}
|
||||
@@ -340,7 +340,7 @@ function fn_selectListWebMainBannerTypeAJson(){
|
||||
const mainBannerSwiper = new Swiper('.main_banner_swiper', {
|
||||
loop: useMainBannerLoop,
|
||||
slidesPerView: 1,
|
||||
autoplay : {
|
||||
autoplay: {
|
||||
disableOnInteraction: false,
|
||||
},
|
||||
pagination: {
|
||||
@@ -381,24 +381,24 @@ function fn_selectListWebMainBannerTypeAJson(){
|
||||
}
|
||||
}
|
||||
|
||||
}else{$("#mainBannerList").empty();}
|
||||
}else if('-2' == data.msgCode){
|
||||
modalEvent.danger("로그인 오류", data.msgDesc, function(){
|
||||
} else { $("#mainBannerList").empty(); }
|
||||
} else if ('-2' == data.msgCode) {
|
||||
modalEvent.danger("로그인 오류", data.msgDesc, function () {
|
||||
fn_leftFormAction('/weblogin/logout.do');
|
||||
});
|
||||
}else{
|
||||
} else {
|
||||
modalEvent.danger("조회 오류", data.msgDesc);
|
||||
}
|
||||
|
||||
},
|
||||
error : function(xhr, status, error) {
|
||||
error: function (xhr, status, error) {
|
||||
modalEvent.danger("조회 오류", "조회 중 오류가 발생하였습니다. 잠시후 다시시도하십시오.");
|
||||
},
|
||||
beforeSend:function(){
|
||||
beforeSend: function () {
|
||||
// 로딩열기
|
||||
$(".loading-image-layer").show();
|
||||
},
|
||||
complete:function(){
|
||||
complete: function () {
|
||||
// 로딩닫기
|
||||
$(".loading-image-layer").hide();
|
||||
}
|
||||
@@ -408,7 +408,7 @@ function fn_selectListWebMainBannerTypeAJson(){
|
||||
/****************************************************************************
|
||||
* 서브 배너 이벤트 리스트 조회
|
||||
****************************************************************************/
|
||||
function fn_selectListWebMainBannerTypeBJson(){
|
||||
function fn_selectListWebMainBannerTypeBJson() {
|
||||
let formData = new FormData();
|
||||
formData.append('bannerType', 'PB');
|
||||
|
||||
@@ -420,8 +420,8 @@ function fn_selectListWebMainBannerTypeBJson(){
|
||||
contentType: false,
|
||||
type: 'POST',
|
||||
async: true,
|
||||
success: function(data){
|
||||
if(data.msgCode=='0'){
|
||||
success: function (data) {
|
||||
if (data.msgCode == '0') {
|
||||
let totalCount = data.rows.length;
|
||||
|
||||
if (0 < totalCount) {
|
||||
@@ -435,8 +435,8 @@ function fn_selectListWebMainBannerTypeBJson(){
|
||||
// 이미지와 링크를 a 태그로 감싸기 (url 파라미터 사용)
|
||||
listHTML += '<div class="swiper-slide" style="background:' + backgroundColor + ';" aria-label="' + currentAriaLabel + '">';
|
||||
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="mb" src="' + CDN_URL + data.rows[i].mobileFilePath + '" 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 += ' <button class="detail_btn">Detail view ></button>';
|
||||
listHTML += ' </a>';
|
||||
listHTML += '</div>';
|
||||
@@ -450,7 +450,7 @@ function fn_selectListWebMainBannerTypeBJson(){
|
||||
const subBannerSwiper = new Swiper('.sub_banner_swiper', {
|
||||
loop: useSubBannerLoop,
|
||||
slidesPerView: 1,
|
||||
autoplay : {
|
||||
autoplay: {
|
||||
disableOnInteraction: false,
|
||||
},
|
||||
pagination: {
|
||||
@@ -495,24 +495,24 @@ function fn_selectListWebMainBannerTypeBJson(){
|
||||
});
|
||||
}
|
||||
|
||||
}else{$("#subBannerList").empty();}
|
||||
}else if('-2' == data.msgCode){
|
||||
modalEvent.danger("로그인 오류", data.msgDesc, function(){
|
||||
} else { $("#subBannerList").empty(); }
|
||||
} else if ('-2' == data.msgCode) {
|
||||
modalEvent.danger("로그인 오류", data.msgDesc, function () {
|
||||
fn_leftFormAction('/weblogin/logout.do');
|
||||
});
|
||||
}else{
|
||||
} else {
|
||||
modalEvent.danger("조회 오류", data.msgDesc);
|
||||
}
|
||||
|
||||
},
|
||||
error : function(xhr, status, error) {
|
||||
error: function (xhr, status, error) {
|
||||
modalEvent.danger("조회 오류", "조회 중 오류가 발생하였습니다. 잠시후 다시시도하십시오.");
|
||||
},
|
||||
beforeSend:function(){
|
||||
beforeSend: function () {
|
||||
// 로딩열기
|
||||
$(".loading-image-layer").show();
|
||||
},
|
||||
complete:function(){
|
||||
complete: function () {
|
||||
// 로딩닫기
|
||||
$(".loading-image-layer").hide();
|
||||
}
|
||||
@@ -522,7 +522,7 @@ function fn_selectListWebMainBannerTypeBJson(){
|
||||
/****************************************************************************
|
||||
* 인스타그램 피드 리스트 조회 (백엔드 API 사용)
|
||||
****************************************************************************/
|
||||
function fn_selectListWebInstagramJson(){
|
||||
function fn_selectListWebInstagramJson() {
|
||||
let formData = new FormData();
|
||||
$.ajax({
|
||||
url: encodeURI('/webinstagram/selectListWebInstagram.do'),
|
||||
@@ -532,8 +532,8 @@ function fn_selectListWebInstagramJson(){
|
||||
contentType: false,
|
||||
type: 'POST',
|
||||
async: true,
|
||||
success: function(data){
|
||||
if(data.msgCode=='0'){
|
||||
success: function (data) {
|
||||
if (data.msgCode == '0') {
|
||||
let totalCount = data.rows.length;
|
||||
if (0 < totalCount) {
|
||||
let listHTML = '';
|
||||
@@ -544,12 +544,12 @@ function fn_selectListWebInstagramJson(){
|
||||
let permalink = data.rows[i].permalink;
|
||||
let mediaType = data.rows[i].media_type || '';
|
||||
let thumbnailUrl = data.rows[i].thumbnail_url || mediaUrl;
|
||||
listHTML += '<div class="swiper-slide" aria-label="'+currentAriaLabel+'">';
|
||||
listHTML += ' <a href="'+permalink+'" target="_blank" rel="noopener">';
|
||||
listHTML += '<div class="swiper-slide" aria-label="' + currentAriaLabel + '">';
|
||||
listHTML += ' <a href="' + permalink + '" target="_blank" rel="noopener">';
|
||||
if (mediaType === 'VIDEO' || mediaType === 'REEL') {
|
||||
listHTML += ' <img src="'+thumbnailUrl+'" alt="instagram'+(i+1)+'" />';
|
||||
listHTML += ' <img src="' + thumbnailUrl + '" alt="instagram' + (i + 1) + '" />';
|
||||
} else {
|
||||
listHTML += ' <img src="'+mediaUrl+'" alt="instagram'+(i+1)+'" />';
|
||||
listHTML += ' <img src="' + mediaUrl + '" alt="instagram' + (i + 1) + '" />';
|
||||
}
|
||||
listHTML += ' </a>';
|
||||
listHTML += '</div>';
|
||||
@@ -558,22 +558,22 @@ function fn_selectListWebInstagramJson(){
|
||||
// 커스텀 내비게이션과 연동
|
||||
initInstagramCustomNav(data);
|
||||
}
|
||||
}else if('-2' == data.msgCode){
|
||||
modalEvent.danger("로그인 오류", data.msgDesc, function(){
|
||||
} else if ('-2' == data.msgCode) {
|
||||
modalEvent.danger("로그인 오류", data.msgDesc, function () {
|
||||
fn_leftFormAction('/weblogin/logout.do');
|
||||
});
|
||||
}else{
|
||||
} else {
|
||||
modalEvent.danger("조회 오류", data.msgDesc);
|
||||
}
|
||||
},
|
||||
error : function(xhr, status, error) {
|
||||
error: function (xhr, status, error) {
|
||||
modalEvent.danger("조회 오류", "조회 중 오류가 발생하였습니다. 잠시후 다시시도하십시오.");
|
||||
},
|
||||
beforeSend:function(){
|
||||
beforeSend: function () {
|
||||
// 로딩열기
|
||||
$(".loading-image-layer").show();
|
||||
},
|
||||
complete:function(){
|
||||
complete: function () {
|
||||
// 로딩닫기
|
||||
$(".loading-image-layer").hide();
|
||||
}
|
||||
@@ -601,7 +601,7 @@ function initInstagramCustomNav(data) {
|
||||
const thumbnailUrl = data.rows[dataIndex].thumbnail_url || mediaUrl;
|
||||
const isActive = dataIndex === currentActiveIndex ? 'active' : '';
|
||||
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>`;
|
||||
}
|
||||
document.querySelector('.custom-swiper-thumbs').innerHTML = thumbsHTML;
|
||||
@@ -611,7 +611,7 @@ function initInstagramCustomNav(data) {
|
||||
createThumbnails(0);
|
||||
|
||||
// Swiper 인스턴스
|
||||
setTimeout(function() {
|
||||
setTimeout(function () {
|
||||
const instagramSwiper = new Swiper('.instagram_swiper', {
|
||||
loop: true,
|
||||
autoplay: {
|
||||
@@ -628,7 +628,7 @@ function initInstagramCustomNav(data) {
|
||||
},
|
||||
},
|
||||
on: {
|
||||
slideChange: function() {
|
||||
slideChange: function () {
|
||||
const newIndex = this.realIndex % totalCount;
|
||||
currentActiveIndex = newIndex; // 활성 인덱스 업데이트
|
||||
|
||||
@@ -655,15 +655,15 @@ function initInstagramCustomNav(data) {
|
||||
});
|
||||
|
||||
// 좌우 버튼 이벤트
|
||||
document.querySelector('.custom-swiper-btn.prev').onclick = function() {
|
||||
document.querySelector('.custom-swiper-btn.prev').onclick = function () {
|
||||
instagramSwiper.slidePrev();
|
||||
};
|
||||
document.querySelector('.custom-swiper-btn.next').onclick = function() {
|
||||
document.querySelector('.custom-swiper-btn.next').onclick = function () {
|
||||
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');
|
||||
if (thumb) {
|
||||
const targetIndex = parseInt(thumb.dataset.index);
|
||||
@@ -684,7 +684,7 @@ function initInstagramCustomNav(data) {
|
||||
|
||||
// 활성 썸네일 표시
|
||||
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);
|
||||
thumb.classList.toggle('active', thumbIndex === activeIdx);
|
||||
});
|
||||
@@ -699,16 +699,16 @@ function initInstagramCustomNav(data) {
|
||||
fn_init();
|
||||
|
||||
// 기존 팝업 닫기 버튼 이벤트 (마스킹 기능 추가)
|
||||
document.getElementById('btnPopupClose').addEventListener('click',function (){
|
||||
document.getElementById('btnPopupClose').addEventListener('click', function () {
|
||||
$('.popup').removeClass('open');
|
||||
// *** 배경 마스킹 제거 추가 ***
|
||||
hideBackgroundMask();
|
||||
});
|
||||
|
||||
// 추가 이벤트 리스너들 (새로 추가)
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
// ESC 키로 팝업 닫기
|
||||
document.addEventListener('keydown', function(e) {
|
||||
document.addEventListener('keydown', function (e) {
|
||||
if (e.key === 'Escape' && document.querySelector('.popup.open')) {
|
||||
$('.popup').removeClass('open');
|
||||
hideBackgroundMask();
|
||||
@@ -718,7 +718,7 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
// 마스크 영역 클릭 시 팝업 닫기 (선택사항)
|
||||
const mask = document.querySelector('.popup-background-mask');
|
||||
if (mask) {
|
||||
mask.addEventListener('click', function() {
|
||||
mask.addEventListener('click', function () {
|
||||
$('.popup').removeClass('open');
|
||||
hideBackgroundMask();
|
||||
});
|
||||
|
||||
@@ -189,12 +189,13 @@ function fn_RenderServices(services) {
|
||||
|
||||
let servicesHtml = '';
|
||||
services.forEach(function(service) {
|
||||
|
||||
servicesHtml += `
|
||||
<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-description">${service.SERVICE_DESC || service.CONTENT || '설명 없음'}</div>
|
||||
<div class="service-price"><span class="cancel-price">${fn_FormatPrice(service.PRICE)}</span> ${fn_FormatPrice(service.DISCOUNT_PRICE)}</div>
|
||||
<div class="service-price">
|
||||
${service.PRICE !== service.DISCOUNT_PRICE ? `<span class="cancel-price">${fn_FormatPrice(service.PRICE)}</span> ` : ''}${fn_FormatPrice(service.DISCOUNT_PRICE)}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
});
|
||||
|
||||
@@ -1,19 +1,16 @@
|
||||
/************************************************
|
||||
* 초기화
|
||||
************************************************/
|
||||
function fn_init() {
|
||||
fn_SelectDetail(category_div_cd, category_no, post_no);
|
||||
// 전역 변수
|
||||
let procedureChoices;
|
||||
let priceList = [];
|
||||
const totalEl = document.getElementById('total');
|
||||
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();
|
||||
formData.append('CATEGORY_DIV_CD', category_div_cd);
|
||||
formData.append('CATEGORY_NO', category_no);
|
||||
@@ -27,210 +24,291 @@ function fn_SelectDetail(category_div_cd, category_no, post_no){
|
||||
contentType: false,
|
||||
type: 'POST',
|
||||
async: true,
|
||||
success: function(data){
|
||||
if(data.msgCode=='0'){
|
||||
//화면 데이터 변경
|
||||
$('#category_nm').text(data.rows.CATEGORY_NM);
|
||||
success: function (data) {
|
||||
if (data.msgCode == '0') {
|
||||
// 화면 데이터 변경
|
||||
$('#title').text(data.rows.TITLE);
|
||||
$('#serviceThumb').attr('src', data.rows.THUMBNAIL_PATH);
|
||||
$('#main_title').text(data.rows.TITLE);
|
||||
$('.thumbnail-bottom-txt').text(data.rows.THUMBNAIL_BOTTOM_TXT);
|
||||
$('#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){
|
||||
$('#startprice').text('0');
|
||||
}else{
|
||||
$('#startprice').text(data.rows.PRICE.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","));
|
||||
}
|
||||
$('#hashtag').text(data.rows.HASHTAG);
|
||||
$('#contents_path').text(data.rows.THUMBNAIL_BOTTOM_TXT);
|
||||
$('#contents_path').attr('src', data.rows.CONTENTS_PATH);
|
||||
//시술 목록 데이터 입력
|
||||
let totalCount = data.price.length;
|
||||
if (0 < totalCount) {
|
||||
for (let i = 0; i < data.price.length; i++) {
|
||||
let listHTML = '';
|
||||
listHTML += '<li class="optipon_item sepr_wrap">';
|
||||
listHTML += ' <div class="item_subprice">';
|
||||
listHTML += ' <div class="cs-checkbox">';
|
||||
listHTML += ' <input type="checkbox" class="idxChk" id="checkboxID' + i + '">';
|
||||
listHTML += ' <label class="cs-checkbox-label d-block" for="checkboxID' + i + '">';
|
||||
listHTML += ' <div class="oi-wrap">';
|
||||
listHTML += ' <div class="oi-txt">';
|
||||
listHTML += ' <span class="oi-tit-txt">' + data.price[i].TREATMENT_PROCEDURE_NAME;
|
||||
listHTML += ' </span>';
|
||||
listHTML += ' </div>';
|
||||
listHTML += ' <div class="oi-price">';
|
||||
listHTML += ' <del class="original_price d-block">';
|
||||
listHTML += ' <b>';
|
||||
if(data.price[i].DISCOUNT_PRICE == null || data.price[i].DISCOUNT_PRICE == undefined){
|
||||
if(data.price[i].PRICE == null || data.price[i].PRICE == undefined){
|
||||
listHTML += '0';
|
||||
}else{
|
||||
listHTML += (data.price[i].PRICE).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
||||
}
|
||||
}else{
|
||||
listHTML += (data.price[i].DISCOUNT_PRICE).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
||||
}
|
||||
listHTML += '</b>원';
|
||||
listHTML += ' </del>';
|
||||
listHTML += ' <span class="discount_price">';
|
||||
if(data.price[i].DISCOUNT_PRICE == null || data.price[i].DISCOUNT_PRICE == undefined){
|
||||
if(data.price[i].PRICE == null || data.price[i].PRICE == undefined){
|
||||
listHTML += '0';
|
||||
}else{
|
||||
listHTML += (data.price[i].PRICE).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
||||
}
|
||||
}else{
|
||||
listHTML += (data.price[i].DISCOUNT_PRICE).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
||||
}
|
||||
listHTML += '</span>원';
|
||||
listHTML += ' </div>';
|
||||
listHTML += ' </div>';
|
||||
listHTML += ' </label>';
|
||||
listHTML += ' </div>';
|
||||
listHTML += ' </div>';
|
||||
listHTML += '</li>';
|
||||
$(".option_list").append(listHTML);
|
||||
|
||||
$("#checkboxID" + i).change(function(){
|
||||
if($("#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, ",");
|
||||
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, ","));
|
||||
}
|
||||
}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);
|
||||
|
||||
// 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);
|
||||
|
||||
}else{
|
||||
listHTML += '<li>';
|
||||
listHTML += '</li>';
|
||||
$(".option_list").html(listHTML);
|
||||
// 이벤트 기간 정보 저장
|
||||
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 + ' ~';
|
||||
}
|
||||
}else{
|
||||
periodEl.textContent = periodText;
|
||||
periodEl.style.display = 'block';
|
||||
}
|
||||
}
|
||||
|
||||
// 시술 목록 데이터 처리
|
||||
updateProcedureOptions(data.price || []);
|
||||
} else {
|
||||
modalEvent.danger("조회 오류", data.msgDesc);
|
||||
}
|
||||
|
||||
},
|
||||
error : function(xhr, status, error) {
|
||||
error: function (xhr, status, error) {
|
||||
modalEvent.danger("조회 오류", "조회 중 오류가 발생하였습니다. 잠시후 다시시도하십시오.");
|
||||
},
|
||||
beforeSend:function(){
|
||||
// 로딩열기
|
||||
beforeSend: function () {
|
||||
$(".loading-image-layer").show();
|
||||
},
|
||||
complete:function(){
|
||||
// 로딩닫기
|
||||
complete: function () {
|
||||
$(".loading-image-layer").hide();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function fn_nocheck(num){
|
||||
$("#checkboxID" + num).prop("checked",false);
|
||||
fn_deleteList(num);
|
||||
/****************************************************************************
|
||||
* 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 fn_deleteList(num){
|
||||
|
||||
var price = $("#price_div1").text().replace(/,/g, "");
|
||||
var discount_price = $("#liid" + num + " > div.info > span > span").text().replace(/,/g, "");
|
||||
|
||||
price = Number(price) - Number(discount_price);
|
||||
$("#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('시술이 선택되지 않았습니다.');
|
||||
/****************************************************************************
|
||||
* 총 금액 업데이트 - 개선된 버전
|
||||
****************************************************************************/
|
||||
function updateTotalPrice() {
|
||||
if (!procedureChoices) {
|
||||
console.log('procedureChoices not initialized');
|
||||
return;
|
||||
}
|
||||
var value = '';
|
||||
for(var i = 0; i < len; i++){
|
||||
value += obj4[i].getAttribute('value') + '#';
|
||||
|
||||
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);
|
||||
}
|
||||
});
|
||||
|
||||
let obj5 = document.createElement('input');
|
||||
obj5.setAttribute('type', 'hidden');
|
||||
obj5.setAttribute('name', 'PROCEDURE_ID');
|
||||
obj5.setAttribute('value', value);
|
||||
pageMoveForm.appendChild(obj5);
|
||||
|
||||
pageMoveForm.setAttribute('method', 'post');
|
||||
pageMoveForm.setAttribute('action', '/webservice/selectMakeReservation.do');
|
||||
document.body.appendChild(pageMoveForm);
|
||||
|
||||
pageMoveForm.submit();
|
||||
|
||||
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();
|
||||
$selectProcedureDiv.not(this).removeClass('active'); /*remove buttonactive from the others*/
|
||||
$(this).toggleClass('active'); /*toggle current clicked element*/
|
||||
/****************************************************************************
|
||||
* 예약 페이지로 이동
|
||||
****************************************************************************/
|
||||
function fn_moveReservation(category_div, category_no, post_no) {
|
||||
if (!procedureChoices) {
|
||||
alert('시술 선택 기능이 초기화되지 않았습니다.');
|
||||
return;
|
||||
}
|
||||
|
||||
const selectedValues = procedureChoices.getValue(true);
|
||||
|
||||
if (selectedValues.length === 0) {
|
||||
alert('시술을 선택해주세요.');
|
||||
return;
|
||||
}
|
||||
|
||||
const form = document.createElement('form');
|
||||
form.method = 'post';
|
||||
form.action = '/webevent/selectMakeReservation.do';
|
||||
|
||||
// 기본 파라미터 추가
|
||||
const params = [
|
||||
{ name: 'CATEGORY_DIV_CD', value: category_div },
|
||||
{ name: 'CATEGORY_NO', value: category_no },
|
||||
{ name: 'POST_NO', value: post_no },
|
||||
{ name: 'EVENT_START_DT', value: window.eventStartDt || '' },
|
||||
{ name: 'EVENT_END_DT', value: window.eventEndDt || '' }
|
||||
];
|
||||
|
||||
params.forEach(param => {
|
||||
const input = document.createElement('input');
|
||||
input.type = 'hidden';
|
||||
input.name = param.name;
|
||||
input.value = param.value;
|
||||
form.appendChild(input);
|
||||
});
|
||||
|
||||
// 선택된 시술 추가
|
||||
selectedValues.forEach(value => {
|
||||
const input = document.createElement('input');
|
||||
input.type = 'hidden';
|
||||
input.name = 'PROCEDURE_ID';
|
||||
input.value = value;
|
||||
form.appendChild(input);
|
||||
});
|
||||
|
||||
document.body.appendChild(form);
|
||||
form.submit();
|
||||
}
|
||||
|
||||
// 예약 버튼 이벤트
|
||||
reserveBtn.addEventListener('click', function () {
|
||||
fn_moveReservation(category_div_cd, category_no, post_no);
|
||||
});
|
||||
|
||||
$(window).on("click", function(){
|
||||
$selectProcedureDiv.removeClass('active');
|
||||
})
|
||||
|
||||
//초기화
|
||||
fn_init();
|
||||
@@ -1,189 +1,216 @@
|
||||
/************************************************
|
||||
* 초기화
|
||||
************************************************/
|
||||
function fn_init() {
|
||||
fn_SelectListCategory();
|
||||
}
|
||||
class EventManager {
|
||||
constructor() {
|
||||
this.events = [];
|
||||
this.categories = [];
|
||||
this.init();
|
||||
}
|
||||
|
||||
async init() {
|
||||
await this.loadCategories();
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* 이벤트 카테고리 목록 가져오기
|
||||
****************************************************************************/
|
||||
function fn_SelectListCategory(){
|
||||
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()
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
let formData = new FormData();
|
||||
async loadCategories() {
|
||||
try {
|
||||
const formData = new FormData();
|
||||
formData.append('bannerType', 'A');
|
||||
const data = await this.apiRequest('/webevent/selectListWebEvent.do', formData);
|
||||
|
||||
$.ajax({
|
||||
url: encodeURI('/webevent/selectListWebEvent.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;
|
||||
|
||||
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>';
|
||||
if (data.msgCode === '0') {
|
||||
this.categories = data.rows;
|
||||
this.renderCategories();
|
||||
if (this.categories.length > 0) {
|
||||
this.loadEvents(this.categories[0].CATEGORY_NO);
|
||||
}
|
||||
}
|
||||
$("#servicecategory").html(listHTML);
|
||||
fn_SelectEventList(data.rows[0].CATEGORY_NO);
|
||||
}
|
||||
}else{
|
||||
} else {
|
||||
modalEvent.danger("조회 오류", data.msgDesc);
|
||||
}
|
||||
|
||||
},
|
||||
error : function(xhr, status, error) {
|
||||
modalEvent.danger("조회 오류", "조회 중 오류가 발생하였습니다. 잠시후 다시시도하십시오.");
|
||||
},
|
||||
beforeSend:function(){
|
||||
// 로딩열기
|
||||
$(".loading-image-layer").show();
|
||||
},
|
||||
complete:function(){
|
||||
// 로딩닫기
|
||||
$(".loading-image-layer").hide();
|
||||
} 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') {
|
||||
const today = new Date();
|
||||
today.setHours(0, 0, 0, 0);
|
||||
|
||||
this.events = data.rows.map(row => {
|
||||
// 지난 이벤트 판별: EVENT_END_DT가 있고 오늘보다 이전이면 expired
|
||||
let isExpired = false;
|
||||
if (row.EVENT_END_DT) {
|
||||
const endDate = new Date(row.EVENT_END_DT);
|
||||
endDate.setHours(23, 59, 59, 999);
|
||||
isExpired = endDate < today;
|
||||
}
|
||||
|
||||
return {
|
||||
img: CDN_URL + row.THUMBNAIL_PATH,
|
||||
title: row.TITLE,
|
||||
desc: row.CONTENT,
|
||||
meta: row.THUMBNAIL_BOTTOM_TXT,
|
||||
price: {
|
||||
before: Number(row.PRICE) || 0,
|
||||
after: Number(row.DISCOUNT_PRICE) || 0
|
||||
},
|
||||
categoryDiv: row.CATEGORY_DIV_CD,
|
||||
categoryNo: row.CATEGORY_NO,
|
||||
postNo: row.POST_NO,
|
||||
eventStartDt: row.EVENT_START_DT,
|
||||
eventEndDt: row.EVENT_END_DT,
|
||||
isExpired: isExpired
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* 시술 목록 가져오기
|
||||
****************************************************************************/
|
||||
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{
|
||||
this.renderEvents();
|
||||
} else {
|
||||
modalEvent.danger("조회 오류", data.msgDesc);
|
||||
}
|
||||
|
||||
},
|
||||
error : function(xhr, status, error) {
|
||||
modalEvent.danger("조회 오류", "조회 중 오류가 발생하였습니다. 잠시후 다시시도하십시오.");
|
||||
},
|
||||
beforeSend:function(){
|
||||
// 로딩열기
|
||||
$(".loading-image-layer").show();
|
||||
},
|
||||
complete:function(){
|
||||
// 로딩닫기
|
||||
$(".loading-image-layer").hide();
|
||||
} 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){
|
||||
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();
|
||||
const eventManager = new EventManager();
|
||||
@@ -0,0 +1,89 @@
|
||||
class ReviewDetailManager {
|
||||
constructor() {
|
||||
this.quill = null;
|
||||
this.init();
|
||||
}
|
||||
|
||||
async init() {
|
||||
if (!muProcedureReviewId) { this.showError('잘못된 접근입니다.'); return; }
|
||||
await this.loadReview();
|
||||
}
|
||||
|
||||
async apiRequest(url, data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
$.ajax({
|
||||
url: encodeURI(url), data: data, dataType: 'json',
|
||||
processData: false, contentType: false, type: 'POST',
|
||||
success: resolve, error: reject
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async loadReview() {
|
||||
try {
|
||||
const formData = new FormData();
|
||||
formData.append('muProcedureReviewId', muProcedureReviewId);
|
||||
const data = await this.apiRequest('/webreview/selectProcedureReview.do', formData);
|
||||
if (data.msgCode === '0' && data.rows) {
|
||||
this.renderReview(data.rows);
|
||||
} else {
|
||||
this.showError('게시글을 찾을 수 없습니다.');
|
||||
}
|
||||
} catch (error) {
|
||||
this.showError('게시글 조회 중 오류가 발생하였습니다.');
|
||||
}
|
||||
}
|
||||
|
||||
renderReview(review) {
|
||||
document.getElementById('review-title').textContent = review.title || '';
|
||||
document.getElementById('breadcrumb-title').textContent = review.title || '상세보기';
|
||||
document.getElementById('review-date').textContent = review.writeDate || '';
|
||||
document.getElementById('review-views').textContent = review.viewCount || 0;
|
||||
|
||||
const tagsContainer = document.getElementById('review-tags');
|
||||
if (review.hashtag) {
|
||||
const tags = review.hashtag.split(',').map(t => t.trim()).filter(t => t);
|
||||
tagsContainer.innerHTML = tags.map(tag => `<span class="review-tag">#${tag}</span>`).join('');
|
||||
}
|
||||
|
||||
// Quill Delta JSON 본문 렌더링
|
||||
const contentDiv = document.getElementById('review-content');
|
||||
if (review.content) {
|
||||
try {
|
||||
const decoded = decodeURIComponent(escape(atob(review.content)));
|
||||
const delta = JSON.parse(decoded);
|
||||
|
||||
contentDiv.innerHTML = '';
|
||||
this.quill = new Quill(contentDiv, {
|
||||
readOnly: true,
|
||||
modules: { toolbar: false },
|
||||
theme: 'snow'
|
||||
});
|
||||
this.quill.setContents(delta);
|
||||
|
||||
const toolbar = contentDiv.parentElement.querySelector('.ql-toolbar');
|
||||
if (toolbar) toolbar.style.display = 'none';
|
||||
const container = contentDiv.parentElement.querySelector('.ql-container');
|
||||
if (container) { container.style.border = 'none'; container.style.fontSize = '16px'; }
|
||||
} catch (e) {
|
||||
try {
|
||||
const html = decodeURIComponent(escape(atob(review.content)));
|
||||
contentDiv.innerHTML = html;
|
||||
} catch (e2) {
|
||||
contentDiv.innerHTML = review.content;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
contentDiv.innerHTML = '<p style="color:#9ca3af;text-align:center;">내용이 없습니다.</p>';
|
||||
}
|
||||
}
|
||||
|
||||
showError(msg) {
|
||||
document.getElementById('review-content').innerHTML = `
|
||||
<div style="text-align:center;padding:3rem;color:#6b7280;">
|
||||
<div style="font-size:2rem;margin-bottom:1rem;">😔</div><div>${msg}</div>
|
||||
</div>`;
|
||||
}
|
||||
}
|
||||
|
||||
const reviewDetailManager = new ReviewDetailManager();
|
||||
@@ -0,0 +1,205 @@
|
||||
class ReviewListManager {
|
||||
constructor() {
|
||||
this.reviews = [];
|
||||
this.currentPage = 1;
|
||||
this.pageSize = 9;
|
||||
this.totalCount = 0;
|
||||
this.categoryDivCd = '08'; // 쁘띠센터
|
||||
this.sliders = {};
|
||||
this.init();
|
||||
}
|
||||
|
||||
async init() {
|
||||
this.bindEvents();
|
||||
await this.loadReviews();
|
||||
}
|
||||
|
||||
bindEvents() {
|
||||
document.getElementById('btnSearch').addEventListener('click', () => {
|
||||
this.currentPage = 1;
|
||||
this.loadReviews();
|
||||
});
|
||||
document.getElementById('searchTitle').addEventListener('keypress', (e) => {
|
||||
if (e.key === 'Enter') { this.currentPage = 1; this.loadReviews(); }
|
||||
});
|
||||
}
|
||||
|
||||
async apiRequest(url, data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
$.ajax({
|
||||
url: encodeURI(url), data: data, dataType: 'json',
|
||||
processData: false, contentType: false, type: 'POST',
|
||||
success: resolve, error: reject
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async loadReviews() {
|
||||
try {
|
||||
const formData = new FormData();
|
||||
formData.append('categoryDivCd', this.categoryDivCd);
|
||||
formData.append('start', (this.currentPage - 1) * this.pageSize);
|
||||
formData.append('limit', this.pageSize);
|
||||
const searchTitle = document.getElementById('searchTitle').value.trim();
|
||||
if (searchTitle) formData.append('title', searchTitle);
|
||||
|
||||
const data = await this.apiRequest('/webreview/selectListProcedureReview.do', formData);
|
||||
if (data.msgCode === '0') {
|
||||
this.reviews = data.rows || [];
|
||||
this.totalCount = parseInt(data.totalCount) || 0;
|
||||
this.renderReviews();
|
||||
this.renderPagination();
|
||||
} else {
|
||||
this.showEmpty('조회 중 오류가 발생하였습니다.');
|
||||
}
|
||||
} catch (error) {
|
||||
this.showEmpty('조회 중 오류가 발생하였습니다.');
|
||||
}
|
||||
}
|
||||
|
||||
extractImages(content) {
|
||||
if (!content) return [];
|
||||
try {
|
||||
const decoded = decodeURIComponent(escape(atob(content)));
|
||||
const delta = JSON.parse(decoded);
|
||||
if (delta.ops) {
|
||||
return delta.ops
|
||||
.filter(op => op.insert && typeof op.insert === 'object' && op.insert.image)
|
||||
.map(op => op.insert.image);
|
||||
}
|
||||
return [];
|
||||
} catch (e) { return []; }
|
||||
}
|
||||
|
||||
extractSummary(content) {
|
||||
if (!content) return '';
|
||||
try {
|
||||
const decoded = decodeURIComponent(escape(atob(content)));
|
||||
const delta = JSON.parse(decoded);
|
||||
if (delta.ops) {
|
||||
const text = delta.ops
|
||||
.filter(op => typeof op.insert === 'string')
|
||||
.map(op => op.insert).join('').replace(/\n/g, ' ').trim();
|
||||
return text.length > 100 ? text.substring(0, 100) + '...' : text;
|
||||
}
|
||||
return '';
|
||||
} catch (e) { return ''; }
|
||||
}
|
||||
|
||||
buildSliderHtml(images, cardIdx) {
|
||||
if (images.length === 0) return '<div class="review-no-image">📷</div>';
|
||||
const imagesHtml = images.map(src => `<img src="${src}" alt="고객후기" loading="lazy" />`).join('');
|
||||
const dotsHtml = images.length > 1
|
||||
? `<div class="slider-dots">${images.map((_, i) =>
|
||||
`<button class="slider-dot ${i === 0 ? 'active' : ''}" data-idx="${i}"></button>`).join('')}</div>` : '';
|
||||
const arrowsHtml = images.length > 1
|
||||
? `<button class="slider-arrow prev" data-dir="-1">‹</button><button class="slider-arrow next" data-dir="1">›</button>` : '';
|
||||
const countHtml = images.length > 1
|
||||
? `<span class="slider-count">1 / ${images.length}</span>` : '';
|
||||
return `<div class="review-slider" data-total="${images.length}" data-current="0">
|
||||
<div class="review-slider-track">${imagesHtml}</div>${arrowsHtml}${dotsHtml}${countHtml}</div>`;
|
||||
}
|
||||
|
||||
renderReviews() {
|
||||
const grid = document.getElementById('review-grid');
|
||||
if (this.reviews.length === 0) {
|
||||
grid.innerHTML = `<div class="empty-state"><div class="icon">📝</div><div class="message">등록된 고객후기가 없습니다.</div></div>`;
|
||||
return;
|
||||
}
|
||||
grid.innerHTML = this.reviews.map((review, idx) => {
|
||||
const images = this.extractImages(review.summary || review.content);
|
||||
const summaryText = this.extractSummary(review.summary || review.content);
|
||||
const sliderHtml = this.buildSliderHtml(images, idx);
|
||||
let tagsHtml = '';
|
||||
if (review.hashtag) {
|
||||
const tags = review.hashtag.split(',').map(t => t.trim()).filter(t => t);
|
||||
tagsHtml = `<div class="review-card-tags">${tags.slice(0, 3).map(tag =>
|
||||
`<span class="review-tag">#${tag}</span>`).join('')}</div>`;
|
||||
}
|
||||
return `<div class="review-card" data-id="${review.muProcedureReviewId}">
|
||||
${sliderHtml}
|
||||
<div class="review-card-body">
|
||||
<div class="review-card-title">${this.escapeHtml(review.title)}</div>
|
||||
<div class="review-card-summary">${summaryText}</div>
|
||||
${tagsHtml}
|
||||
<div class="review-card-footer">
|
||||
<span class="date">${review.writeDate}</span>
|
||||
<span class="views">👁 ${review.viewCount || 0}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>`;
|
||||
}).join('');
|
||||
|
||||
this.bindSliderEvents();
|
||||
|
||||
grid.querySelectorAll('.review-card').forEach(card => {
|
||||
card.addEventListener('click', (e) => {
|
||||
if (e.target.closest('.slider-arrow') || e.target.closest('.slider-dot')) return;
|
||||
location.href = `/webreview/selectProcedureReviewIntro.do?muProcedureReviewId=${card.dataset.id}`;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
bindSliderEvents() {
|
||||
document.querySelectorAll('.review-slider').forEach(slider => {
|
||||
const total = parseInt(slider.dataset.total);
|
||||
if (total <= 1) return;
|
||||
const track = slider.querySelector('.review-slider-track');
|
||||
const dots = slider.querySelectorAll('.slider-dot');
|
||||
const countEl = slider.querySelector('.slider-count');
|
||||
|
||||
const goTo = (idx) => {
|
||||
const current = Math.max(0, Math.min(idx, total - 1));
|
||||
slider.dataset.current = current;
|
||||
track.style.transform = `translateX(-${current * 100}%)`;
|
||||
dots.forEach((d, i) => d.classList.toggle('active', i === current));
|
||||
if (countEl) countEl.textContent = `${current + 1} / ${total}`;
|
||||
};
|
||||
slider.querySelectorAll('.slider-arrow').forEach(arrow => {
|
||||
arrow.addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
let next = parseInt(slider.dataset.current) + parseInt(arrow.dataset.dir);
|
||||
if (next < 0) next = total - 1;
|
||||
if (next >= total) next = 0;
|
||||
goTo(next);
|
||||
});
|
||||
});
|
||||
dots.forEach(dot => {
|
||||
dot.addEventListener('click', (e) => { e.stopPropagation(); goTo(parseInt(dot.dataset.idx)); });
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
renderPagination() {
|
||||
const area = document.getElementById('pagination-area');
|
||||
const totalPages = Math.ceil(this.totalCount / this.pageSize);
|
||||
if (totalPages <= 1) { area.innerHTML = ''; return; }
|
||||
let html = `<button class="page-btn ${this.currentPage === 1 ? 'disabled' : ''}" data-page="${this.currentPage - 1}" ${this.currentPage === 1 ? 'disabled' : ''}>‹</button>`;
|
||||
const startPage = Math.max(1, this.currentPage - 2);
|
||||
const endPage = Math.min(totalPages, startPage + 4);
|
||||
for (let i = startPage; i <= endPage; i++) {
|
||||
html += `<button class="page-btn ${i === this.currentPage ? 'active' : ''}" data-page="${i}">${i}</button>`;
|
||||
}
|
||||
html += `<button class="page-btn ${this.currentPage === totalPages ? 'disabled' : ''}" data-page="${this.currentPage + 1}" ${this.currentPage === totalPages ? 'disabled' : ''}>›</button>`;
|
||||
area.innerHTML = html;
|
||||
area.querySelectorAll('.page-btn:not(.disabled)').forEach(btn => {
|
||||
btn.addEventListener('click', () => {
|
||||
this.currentPage = parseInt(btn.dataset.page);
|
||||
this.loadReviews();
|
||||
window.scrollTo({ top: 0, behavior: 'smooth' });
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
showEmpty(msg) {
|
||||
document.getElementById('review-grid').innerHTML = `<div class="empty-state"><div class="icon">⚠️</div><div class="message">${msg}</div></div>`;
|
||||
document.getElementById('pagination-area').innerHTML = '';
|
||||
}
|
||||
|
||||
escapeHtml(str) {
|
||||
if (!str) return '';
|
||||
return str.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"').replace(/'/g, ''');
|
||||
}
|
||||
}
|
||||
|
||||
const reviewListManager = new ReviewListManager();
|
||||
230
src/main/resources/static/sitemap.xml
Normal file
@@ -0,0 +1,230 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd">
|
||||
<url>
|
||||
<loc>https://petit.madeu.co.kr/</loc>
|
||||
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||
<priority>1.00</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://petit.madeu.co.kr/index</loc>
|
||||
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||
<priority>0.80</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://petit.madeu.co.kr/webintroduction/selectIntroductionHospitalIntro.do</loc>
|
||||
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||
<priority>0.80</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://petit.madeu.co.kr/webintroduction/selectIntroductionStaffIntro.do</loc>
|
||||
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||
<priority>0.80</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://petit.madeu.co.kr/webintroduction/selectIntroductionWayIntro.do</loc>
|
||||
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||
<priority>0.80</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://petit.madeu.co.kr/webservice/selectServiceIntro.do?categoryNo=4</loc>
|
||||
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||
<priority>0.80</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://petit.madeu.co.kr/webservice/selectServiceDetailIntro.do?categoryDivCd=03&categoryNo=4&postNo=8</loc>
|
||||
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||
<priority>0.80</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://petit.madeu.co.kr/webservice/selectServiceDetailIntro.do?categoryDivCd=03&categoryNo=4&postNo=2</loc>
|
||||
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||
<priority>0.80</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://petit.madeu.co.kr/webservice/selectServiceDetailIntro.do?categoryDivCd=03&categoryNo=4&postNo=3</loc>
|
||||
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||
<priority>0.80</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://petit.madeu.co.kr/webservice/selectServiceDetailIntro.do?categoryDivCd=03&categoryNo=4&postNo=4</loc>
|
||||
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||
<priority>0.80</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://petit.madeu.co.kr/webservice/selectServiceDetailIntro.do?categoryDivCd=03&categoryNo=4&postNo=5</loc>
|
||||
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||
<priority>0.80</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://petit.madeu.co.kr/webservice/selectServiceDetailIntro.do?categoryDivCd=03&categoryNo=4&postNo=6</loc>
|
||||
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||
<priority>0.80</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://petit.madeu.co.kr/webservice/selectServiceDetailIntro.do?categoryDivCd=03&categoryNo=4&postNo=7</loc>
|
||||
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||
<priority>0.80</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://petit.madeu.co.kr/webservice/selectServiceIntro.do?categoryNo=2</loc>
|
||||
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||
<priority>0.80</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://petit.madeu.co.kr/webservice/selectServiceDetailIntro.do?categoryDivCd=03&categoryNo=2&postNo=3</loc>
|
||||
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||
<priority>0.80</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://petit.madeu.co.kr/webservice/selectServiceDetailIntro.do?categoryDivCd=03&categoryNo=2&postNo=4</loc>
|
||||
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||
<priority>0.80</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://petit.madeu.co.kr/webservice/selectServiceDetailIntro.do?categoryDivCd=03&categoryNo=2&postNo=5</loc>
|
||||
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||
<priority>0.80</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://petit.madeu.co.kr/webservice/selectServiceIntro.do?categoryNo=3</loc>
|
||||
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||
<priority>0.80</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://petit.madeu.co.kr/webservice/selectServiceDetailIntro.do?categoryDivCd=03&categoryNo=3&postNo=6</loc>
|
||||
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||
<priority>0.80</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://petit.madeu.co.kr/webservice/selectServiceDetailIntro.do?categoryDivCd=03&categoryNo=3&postNo=10</loc>
|
||||
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||
<priority>0.80</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://petit.madeu.co.kr/webservice/selectServiceDetailIntro.do?categoryDivCd=03&categoryNo=3&postNo=11</loc>
|
||||
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||
<priority>0.80</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://petit.madeu.co.kr/webservice/selectServiceIntro.do?categoryNo=5</loc>
|
||||
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||
<priority>0.80</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://petit.madeu.co.kr/webservice/selectServiceDetailIntro.do?categoryDivCd=03&categoryNo=5&postNo=5</loc>
|
||||
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||
<priority>0.80</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://petit.madeu.co.kr/webservice/selectServiceDetailIntro.do?categoryDivCd=03&categoryNo=5&postNo=6</loc>
|
||||
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||
<priority>0.80</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://petit.madeu.co.kr/webservice/selectServiceDetailIntro.do?categoryDivCd=03&categoryNo=5&postNo=7</loc>
|
||||
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||
<priority>0.80</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://petit.madeu.co.kr/webservice/selectServiceDetailIntro.do?categoryDivCd=03&categoryNo=5&postNo=8</loc>
|
||||
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||
<priority>0.80</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://petit.madeu.co.kr/webservice/selectServiceDetailIntro.do?categoryDivCd=03&categoryNo=5&postNo=9</loc>
|
||||
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||
<priority>0.80</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://petit.madeu.co.kr/webservice/selectServiceIntro.do?categoryNo=1</loc>
|
||||
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||
<priority>0.80</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://petit.madeu.co.kr/webservice/selectServiceDetailIntro.do?categoryDivCd=03&categoryNo=1&postNo=10</loc>
|
||||
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||
<priority>0.80</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://petit.madeu.co.kr/webservice/selectServiceDetailIntro.do?categoryDivCd=03&categoryNo=1&postNo=3</loc>
|
||||
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||
<priority>0.80</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://petit.madeu.co.kr/webservice/selectServiceDetailIntro.do?categoryDivCd=03&categoryNo=1&postNo=6</loc>
|
||||
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||
<priority>0.80</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://petit.madeu.co.kr/webservice/selectServiceDetailIntro.do?categoryDivCd=03&categoryNo=1&postNo=11</loc>
|
||||
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||
<priority>0.80</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://petit.madeu.co.kr/webservice/selectServiceIntro.do?categoryNo=6</loc>
|
||||
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||
<priority>0.80</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://petit.madeu.co.kr/webservice/selectServiceDetailIntro.do?categoryDivCd=03&categoryNo=6&postNo=7</loc>
|
||||
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||
<priority>0.80</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://petit.madeu.co.kr/webservice/selectServiceDetailIntro.do?categoryDivCd=03&categoryNo=6&postNo=8</loc>
|
||||
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||
<priority>0.80</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://petit.madeu.co.kr/webservice/selectServiceDetailIntro.do?categoryDivCd=03&categoryNo=6&postNo=9</loc>
|
||||
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||
<priority>0.80</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://petit.madeu.co.kr/webservice/selectServiceDetailIntro.do?categoryDivCd=03&categoryNo=6&postNo=10</loc>
|
||||
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||
<priority>0.80</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://petit.madeu.co.kr/webservice/selectServiceDetailIntro.do?categoryDivCd=03&categoryNo=6&postNo=11</loc>
|
||||
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||
<priority>0.80</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://petit.madeu.co.kr/webservice/selectServiceIntro.do?categoryNo=7</loc>
|
||||
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||
<priority>0.80</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://petit.madeu.co.kr/webservice/selectServiceDetailIntro.do?categoryDivCd=03&categoryNo=7&postNo=8</loc>
|
||||
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||
<priority>0.80</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://petit.madeu.co.kr/webservice/selectServiceDetailIntro.do?categoryDivCd=03&categoryNo=7&postNo=9</loc>
|
||||
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||
<priority>0.80</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://petit.madeu.co.kr/webevent/selectListWebEventIntro.do</loc>
|
||||
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||
<priority>0.80</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://petit.madeu.co.kr/webphoto/selectListWebPhotoIntro.do</loc>
|
||||
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||
<priority>0.80</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://petit.madeu.co.kr/webaccept/acceptSite.do</loc>
|
||||
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||
<priority>0.80</priority>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://petit.madeu.co.kr/webaccept/acceptPrivacy.do</loc>
|
||||
<lastmod>2026-01-19T10:12:59+00:00</lastmod>
|
||||
<priority>0.80</priority>
|
||||
</url>
|
||||
</urlset>
|
||||
@@ -1,15 +1,13 @@
|
||||
<!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}">
|
||||
<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" href="/css/web/index.css">
|
||||
<link rel="stylesheet" href="/css/web/instagram-swiper-custom.css?v1.0">
|
||||
</th:block>
|
||||
<th:block layout:fragment="layoutContent">
|
||||
<div class="popup-background-mask"></div>
|
||||
<main>
|
||||
<div class="popup-background-mask"></div>
|
||||
<main>
|
||||
<section class="banner main_banner">
|
||||
<div class="swiper main_banner_swiper">
|
||||
<div class="swiper-wrapper" id="mainBannerList">
|
||||
@@ -25,24 +23,24 @@
|
||||
<div class="swiper cont1_swiper">
|
||||
<div class="swiper-wrapper">
|
||||
<div class="swiper-slide">
|
||||
<img class="pc" src="/image/web/petit_content_lifting.JPG" alt="img">
|
||||
<img class="mb" src="/image/web/petit_content_lifting.JPG" alt="img">
|
||||
<img class="pc" src="/image/signature/20251024/레이저리프팅.jpg" alt="img">
|
||||
<img class="mb" src="/image/signature/20251024/레이저리프팅.jpg" alt="img">
|
||||
</div>
|
||||
<div class="swiper-slide">
|
||||
<img class="pc" src="/image/web/petit_content_botox.JPG" alt="img">
|
||||
<img class="mb" src="/image/web/petit_content_botox.JPG" alt="img">
|
||||
<img class="pc" src="/image/signature/20251024/쉬다주사(Face).jpg" alt="img">
|
||||
<img class="mb" src="/image/signature/20251024/쉬다주사(Face).jpg" alt="img">
|
||||
</div>
|
||||
<div class="swiper-slide">
|
||||
<img class="pc" src="/image/web/petit_content_booster.JPG" alt="img">
|
||||
<img class="mb" src="/image/web/petit_content_booster.JPG" alt="img">
|
||||
<img class="pc" src="/image/signature/20251024/스컬트라.jpg" alt="img">
|
||||
<img class="mb" src="/image/signature/20251024/스컬트라.jpg" alt="img">
|
||||
</div>
|
||||
<div class="swiper-slide">
|
||||
<img class="pc" src="/image/web/petit_content_waxing.JPG" alt="img">
|
||||
<img class="mb" src="/image/web/petit_content_waxing.JPG" alt="img">
|
||||
<img class="pc" src="/image/signature/20251024/스킨부스터.jpg" alt="img">
|
||||
<img class="mb" src="/image/signature/20251024/스킨부스터.jpg" alt="img">
|
||||
</div>
|
||||
<div class="swiper-slide">
|
||||
<img class="pc" src="/image/web/petit_content_filler.JPG" alt="img">
|
||||
<img class="mb" src="/image/web/petit_content_filler.JPG" alt="img">
|
||||
<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>
|
||||
@@ -73,24 +71,28 @@
|
||||
<div class="swiper cont2_swiper">
|
||||
<div class="swiper-wrapper">
|
||||
<div class="swiper-slide">
|
||||
<img class="pc" src="/image/web/petit_machine_thermage.jpg" alt="img" style="cursor:pointer">
|
||||
<img class="mb" src="/image/web/petit_machine_thermage.jpg" alt="img" style="cursor:pointer">
|
||||
<img class="pc" src="/image/equip/20260313/써마지FLX.jpg" alt="img" style="cursor:pointer">
|
||||
<img class="mb" src="/image/equip/20260313/써마지FLX.jpg" alt="img" style="cursor:pointer">
|
||||
</div>
|
||||
<div class="swiper-slide">
|
||||
<img class="pc" src="/image/web/petit_machine_ultherapy.jpg" alt="img" style="cursor:pointer">
|
||||
<img class="mb" src="/image/web/petit_machine_ultherapy.jpg" alt="img" style="cursor:pointer">
|
||||
<img class="pc" src="/image/equip/20260313/울쎄라.jpg" alt="img" style="cursor:pointer">
|
||||
<img class="mb" src="/image/equip/20260313/울쎄라.jpg" alt="img" style="cursor:pointer">
|
||||
</div>
|
||||
<div class="swiper-slide">
|
||||
<img class="pc" src="/image/web/petit_machine_stemcell.jpg" alt="img" style="cursor:pointer">
|
||||
<img class="mb" src="/image/web/petit_machine_stemcell.jpg" alt="img" style="cursor:pointer">
|
||||
<img class="pc" src="/image/equip/20260313/온다리프팅(Face).jpg" alt="img"
|
||||
style="cursor:pointer">
|
||||
<img class="mb" src="/image/equip/20260313/온다리프팅(Face).jpg" alt="img"
|
||||
style="cursor:pointer">
|
||||
</div>
|
||||
<div class="swiper-slide">
|
||||
<img class="pc" src="/image/web/petit_machine_tuneface.jpg" alt="img" style="cursor:pointer">
|
||||
<img class="mb" src="/image/web/petit_machine_tuneface.jpg" alt="img" style="cursor:pointer">
|
||||
<img class="pc" src="/image/equip/20260313/티타늄리프팅(Face).jpg" alt="img"
|
||||
style="cursor:pointer">
|
||||
<img class="mb" src="/image/equip/20260313/티타늄리프팅(Face).jpg" alt="img"
|
||||
style="cursor:pointer">
|
||||
</div>
|
||||
<div class="swiper-slide">
|
||||
<img class="pc" src="/image/web/petit_machine_lifting.jpg" alt="img" style="cursor:pointer">
|
||||
<img class="mb" src="/image/web/petit_machine_lifting.jpg" alt="img" style="cursor:pointer">
|
||||
<img class="pc" src="/image/equip/20260313/튠페이스.jpg" alt="img" style="cursor:pointer">
|
||||
<img class="mb" src="/image/equip/20260313/튠페이스.jpg" alt="img" style="cursor:pointer">
|
||||
</div>
|
||||
</div>
|
||||
<div class="swiper-pagination cont2_swiper_pagination"></div>
|
||||
@@ -101,10 +103,11 @@
|
||||
<div class="swiper-area">
|
||||
<div class="instagram_top">
|
||||
<h3>
|
||||
MADE U 인스타그램<br/>
|
||||
MADE U 인스타그램<br />
|
||||
<span>@madeu_gn</span>
|
||||
</h3>
|
||||
<button class="more_btn" onClick="window.open('https://instagram.com/madeu_gn')">View more ≫</button>
|
||||
<button class="more_btn" onClick="window.open('https://instagram.com/madeu_gn')">View more
|
||||
≫</button>
|
||||
</div>
|
||||
<div class="instagram_btm" id="instagramFeed">
|
||||
<div class="swiper instagram_swiper">
|
||||
@@ -120,24 +123,24 @@
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
</main>
|
||||
|
||||
<!-- 팝업 -->
|
||||
<div class="popup">
|
||||
<!-- 팝업 -->
|
||||
<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"/>
|
||||
<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>
|
||||
<button class="close_btn_btm" id="btnPopupClose"><img src="/image/web/close.png" alt="close" /></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</th:block>
|
||||
<th:block layout:fragment="layoutContentScript">
|
||||
@@ -147,4 +150,5 @@
|
||||
</script>
|
||||
<script src="/js/web/index.js"></script>
|
||||
</th:block>
|
||||
|
||||
</html>
|
||||
@@ -1,8 +1,6 @@
|
||||
<!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}">
|
||||
<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" href="/css/web/introduction/introductionHospitalSelect.css?v1.0">
|
||||
</th:block>
|
||||
@@ -10,16 +8,16 @@
|
||||
<main>
|
||||
<section class="main_img">
|
||||
<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">
|
||||
<p class="hashtag">#맞춤진료 #만족스러운결과</p>
|
||||
<p class="title">
|
||||
<span>MADE U 강남본점</span><br/>
|
||||
Total Beauty<br class="mb"/> One Stop System
|
||||
<span>MADE U 강남본점</span><br />
|
||||
Total Beauty<br class="mb" /> One Stop System
|
||||
</p>
|
||||
<p class="sub_text">
|
||||
한 공간에서 고객 한분 한분께 자연스러운<br class="mb"/> 아름다움과 건강한 다이어트를 위해<br/>
|
||||
항상 노력하는 함께하는<br class="mb"/> 조언자가 되어 드릴 것을 약속드립니다.
|
||||
한 공간에서 고객 한분 한분께 자연스러운<br class="mb" /> 아름다움과 건강한 다이어트를 위해<br />
|
||||
항상 노력하는 함께하는<br class="mb" /> 조언자가 되어 드릴 것을 약속드립니다.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -28,47 +26,47 @@
|
||||
<div class="inner_wrap">
|
||||
<div class="text_box">
|
||||
<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">
|
||||
쾌적하고 안락한 공간을 제공하는<br/>
|
||||
쾌적하고 안락한 공간을 제공하는<br />
|
||||
<span>메이드유 강남본점</span>
|
||||
</p>
|
||||
<p class="sub_text">
|
||||
깨끗한 공간, 친절한 상담을 제공<span class="pc">하겠습니다.</span>
|
||||
</p>
|
||||
</div>
|
||||
<img src="/image/web/introduction_content1.png" alt="content1"/>
|
||||
<img src="/image/web/introduction_content1.png" alt="content1" />
|
||||
</div>
|
||||
</section>
|
||||
<section class="content2">
|
||||
<div class="inner_wrap">
|
||||
<p class="mb">쉬운다이어트 방법 없을까?<br/><span>MADE U 시그니처 프로그램</span></p>
|
||||
<p class="mb">쉬운다이어트 방법 없을까?<br /><span>MADE U 시그니처 프로그램</span></p>
|
||||
<ul>
|
||||
<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">
|
||||
<p>One-On-One Customized Counseling</p>
|
||||
<p class="sub_title">
|
||||
MADE U 강남본점만의<br/>
|
||||
MADE U 강남본점만의<br />
|
||||
<span>1:1 맞춤 상담</span>
|
||||
</p>
|
||||
<p class="sub_text">
|
||||
고객님의 체형별 그리고 고민<br class="mb"/> 부위별 맞춤진료로,<br/>
|
||||
고객님의 체형별 그리고 고민<br class="mb" /> 부위별 맞춤진료로,<br />
|
||||
숨겨진 아름다움을 찾아드립니다.
|
||||
</p>
|
||||
</div>
|
||||
</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">
|
||||
<p>Trademark Application</p>
|
||||
<p class="sub_title">
|
||||
MADE U 강남본점만의<br/>
|
||||
MADE U 강남본점만의<br />
|
||||
<span>특허<span class="red">✓</span>상표 출원</span>
|
||||
</p>
|
||||
<p class="sub_text">
|
||||
메이드유 강남본점에서 자체 개발한<br class="mb"/> 메쉬다 주사<br class="pc"/>
|
||||
레시피의 뛰어난<br class="mb"/> 효과를 바탕으로 다수의<br/>
|
||||
메이드유 강남본점에서 자체 개발한<br class="mb" /> 메쉬다 주사<br class="pc" />
|
||||
레시피의 뛰어난<br class="mb" /> 효과를 바탕으로 다수의<br />
|
||||
특허와 상표를 등록했습니다.
|
||||
</p>
|
||||
</div>
|
||||
@@ -87,7 +85,7 @@
|
||||
</div>
|
||||
<div class="equipment-info">
|
||||
<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>
|
||||
</div>
|
||||
</div>
|
||||
@@ -98,7 +96,7 @@
|
||||
</div>
|
||||
<div class="equipment-info">
|
||||
<h3 class="equipment-name">울쎄라</h3>
|
||||
<p class="equipment-desc">깊은 탄력과 리프팅을 동시에</p>
|
||||
<!-- <p class="equipment-desc">깊은 탄력과 리프팅을 동시에</p> -->
|
||||
<p class="equipment-price"><!-- 400,000<span>부터</span> --></p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -109,18 +107,27 @@
|
||||
</div>
|
||||
<div class="equipment-info">
|
||||
<h3 class="equipment-name">티타늄리프팅</h3>
|
||||
<p class="equipment-desc">깊은 탄력과 리프팅을 동시에</p>
|
||||
<!-- <p class="equipment-desc">깊은 탄력과 리프팅을 동시에</p> -->
|
||||
<p class="equipment-price"><!-- 600,000<span>부터</span> --></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="equipment-card">
|
||||
<div class="equipment-image">
|
||||
<img src="/image/equip/온다리프팅.jpg" alt="온다리프팅">
|
||||
</div>
|
||||
<div class="equipment-info">
|
||||
<h3 class="equipment-name">온다리프팅</h3>
|
||||
<!-- <p class="equipment-desc">깊은 탄력과 리프팅을 동시에</p> -->
|
||||
<!-- <p class="equipment-price">165,000<span>부터</span></p> -->
|
||||
</div>
|
||||
</div>
|
||||
<div class="equipment-card">
|
||||
<div class="equipment-image">
|
||||
<img src="/image/equip/튠바디.jpg" alt="튠바디">
|
||||
</div>
|
||||
<div class="equipment-info">
|
||||
<h3 class="equipment-name">튠바디</h3>
|
||||
<p class="equipment-desc">깊은 탄력과 리프팅을 동시에</p>
|
||||
<!-- <p class="equipment-desc">깊은 탄력과 리프팅을 동시에</p> -->
|
||||
<p class="equipment-price"><!-- 150,000<span>부터</span> --></p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -132,7 +139,7 @@
|
||||
</div>
|
||||
<div class="equipment-info">
|
||||
<h3 class="equipment-name">튠페이스</h3>
|
||||
<p class="equipment-desc">깊은 탄력과 리프팅을 동시에</p>
|
||||
<!-- <p class="equipment-desc">깊은 탄력과 리프팅을 동시에</p> -->
|
||||
<p class="equipment-price"><!-- 400,000<span>부터</span> --></p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -143,7 +150,7 @@
|
||||
</div>
|
||||
<div class="equipment-info">
|
||||
<h3 class="equipment-name">울핏</h3>
|
||||
<p class="equipment-desc">깊은 탄력과 리프팅을 동시에</p>
|
||||
<!-- <p class="equipment-desc">깊은 탄력과 리프팅을 동시에</p> -->
|
||||
<p class="equipment-price"><!-- 50,000<span>부터</span> --></p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -154,7 +161,7 @@
|
||||
</div>
|
||||
<div class="equipment-info">
|
||||
<h3 class="equipment-name">포텐자</h3>
|
||||
<p class="equipment-desc">깊은 탄력과 리프팅을 동시에</p>
|
||||
<!-- <p class="equipment-desc">깊은 탄력과 리프팅을 동시에</p> -->
|
||||
<p class="equipment-price"><!-- 150,000<span>부터</span> --></p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -165,7 +172,7 @@
|
||||
</div>
|
||||
<div class="equipment-info">
|
||||
<h3 class="equipment-name">인모드</h3>
|
||||
<p class="equipment-desc">깊은 탄력과 리프팅을 동시에</p>
|
||||
<!-- <p class="equipment-desc">깊은 탄력과 리프팅을 동시에</p> -->
|
||||
<p class="equipment-price"><!-- 100,000<span>부터</span> --></p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -177,7 +184,7 @@
|
||||
</div>
|
||||
<div class="equipment-info">
|
||||
<h3 class="equipment-name">슈링크유니버스</h3>
|
||||
<p class="equipment-desc">깊은 탄력과 리프팅을 동시에</p>
|
||||
<!-- <p class="equipment-desc">깊은 탄력과 리프팅을 동시에</p> -->
|
||||
<p class="equipment-price"><!-- 89,000<span>부터</span> --></p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -188,7 +195,7 @@
|
||||
</div>
|
||||
<div class="equipment-info">
|
||||
<h3 class="equipment-name">바디고주파테라피</h3>
|
||||
<p class="equipment-desc">깊은 탄력과 리프팅을 동시에</p>
|
||||
<!-- <p class="equipment-desc">깊은 탄력과 리프팅을 동시에</p> -->
|
||||
<p class="equipment-price"><!-- 100,000<span>부터</span> --></p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -199,21 +206,12 @@
|
||||
</div>
|
||||
<div class="equipment-info">
|
||||
<h3 class="equipment-name">리포덤</h3>
|
||||
<p class="equipment-desc">깊은 탄력과 리프팅을 동시에</p>
|
||||
<!-- <p class="equipment-desc">깊은 탄력과 리프팅을 동시에</p> -->
|
||||
<p class="equipment-price"><!-- 50,000<span>부터</span> --></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="equipment-card">
|
||||
<div class="equipment-image">
|
||||
<img src="/image/equip/라비앙.jpg" alt="라비앙">
|
||||
</div>
|
||||
<div class="equipment-info">
|
||||
<h3 class="equipment-name">라비앙</h3>
|
||||
<p class="equipment-desc">깊은 탄력과 리프팅을 동시에</p>
|
||||
<p class="equipment-price"><!-- 165,000<span>부터</span> --></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@@ -221,7 +219,7 @@
|
||||
<section class="content4">
|
||||
<div class="inner_wrap">
|
||||
<p>
|
||||
한 공간에서 고객 한분 한분께 자연스러운 아름다움과<br class="mb"/> 건강한 다이어트를 위해 항상 노력하는<br/>
|
||||
한 공간에서 고객 한분 한분께 자연스러운 아름다움과<br class="mb" /> 건강한 다이어트를 위해 항상 노력하는<br />
|
||||
<span>Total Beauty One Stop System</span>
|
||||
</p>
|
||||
<ul>
|
||||
@@ -229,56 +227,57 @@
|
||||
<div class="text_box">
|
||||
<p>
|
||||
<span>
|
||||
자연스러운 아름다움과<br/>
|
||||
자연스러운 아름다움과<br />
|
||||
건강한 다이어트
|
||||
</span>
|
||||
</p>
|
||||
<p>
|
||||
메이드유는 <span>Total Beauty One Stop System</span>으로<br class="pc"/>
|
||||
한 공간에서 고객 한분 <br class="mb"/>한분께 자연스러운 아름다움과<br/>
|
||||
건강한 다이어트를 위해 항상 노력하는 함께하는 조언자가<br class="pc"/>
|
||||
메이드유는 <span>Total Beauty One Stop System</span>으로<br class="pc" />
|
||||
한 공간에서 고객 한분 <br class="mb" />한분께 자연스러운 아름다움과<br />
|
||||
건강한 다이어트를 위해 항상 노력하는 함께하는 조언자가<br class="pc" />
|
||||
되어 드릴 것을 약속드립니다.
|
||||
</p>
|
||||
</div>
|
||||
<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="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" />
|
||||
</li>
|
||||
<li class="red_box">
|
||||
<div class="text_box">
|
||||
<p>
|
||||
<span>고객을 가족으로 생각하는 마음으로<br class="pc"/>정직한 시술, <br class="mb"/>만족할 수 있는 결과,</span><br/>
|
||||
더 나은 감동을 선사하기 위해<br/>
|
||||
<span>고객을 가족으로 생각하는 마음으로<br class="pc" />정직한 시술, <br class="mb" />만족할 수 있는
|
||||
결과,</span><br />
|
||||
더 나은 감동을 선사하기 위해<br />
|
||||
끊임없이 노력하겠습니다.
|
||||
</p>
|
||||
<p>
|
||||
메이드유는 <span>전국, 해외에서 찾아오는 비만센터와<br class="pc"/> 프리미멈 명품
|
||||
장비 보유 및 장비 최다 보유</span>와 엘란쎄, <br class="pc"/>스컬트라 콜라겐 볼륨
|
||||
전국 3대 병원인 쁘띠 센터로 <br class="pc"/>구분되어 고객에 맞춰 운영되고
|
||||
메이드유는 <span>전국, 해외에서 찾아오는 비만센터와<br class="pc" /> 프리미멈 명품
|
||||
장비 보유 및 장비 최다 보유</span>와 엘란쎄, <br class="pc" />스컬트라 콜라겐 볼륨
|
||||
전국 3대 병원인 쁘띠 센터로 <br class="pc" />구분되어 고객에 맞춰 운영되고
|
||||
있습니다.
|
||||
</p>
|
||||
</div>
|
||||
<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="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" />
|
||||
</li>
|
||||
<li>
|
||||
<div class="text_box">
|
||||
<p>
|
||||
No Pain 통증 없이<br/>
|
||||
No Bruise 멍 없이<br/>
|
||||
No Swelling 붓기 없이<br/>
|
||||
No Pain 통증 없이<br />
|
||||
No Bruise 멍 없이<br />
|
||||
No Swelling 붓기 없이<br />
|
||||
<span>3No 의료서비스를 지향</span>
|
||||
</p>
|
||||
<p>
|
||||
모든 제품은 정품, 정량, 정품 장비 사용을 원칙으로 안전을 <br class="pc"/>
|
||||
최우선으로 하고 있으며, 모든 시술은 <span>No Pain, No Bruise, <br class="pc"/>
|
||||
No Swelling라는 3No 의료서비스를 지향</span>합니다. <br class="pc"/>
|
||||
앞으로도 고품질의 관리와 서비스를 받을 수 있도록 노력하며 <br class="pc"/>
|
||||
사소한 불편까지 읽어주는 세심한 배려, 마음까지 읽는 서비스로<br class="pc"/>
|
||||
모든 제품은 정품, 정량, 정품 장비 사용을 원칙으로 안전을 <br class="pc" />
|
||||
최우선으로 하고 있으며, 모든 시술은 <span>No Pain, No Bruise, <br class="pc" />
|
||||
No Swelling라는 3No 의료서비스를 지향</span>합니다. <br class="pc" />
|
||||
앞으로도 고품질의 관리와 서비스를 받을 수 있도록 노력하며 <br class="pc" />
|
||||
사소한 불편까지 읽어주는 세심한 배려, 마음까지 읽는 서비스로<br class="pc" />
|
||||
무한 감동을 드릴 것을 약속합니다.
|
||||
</p>
|
||||
</div>
|
||||
<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="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" />
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
@@ -287,4 +286,5 @@
|
||||
</th:block>
|
||||
<th:block layout:fragment="layoutContentScript">
|
||||
</th:block>
|
||||
|
||||
</html>
|
||||
@@ -34,9 +34,9 @@
|
||||
<li>
|
||||
<img src="/image/web/profile1.jpg" alt="profile"/>
|
||||
<div class="text_box">
|
||||
<p class="field">
|
||||
<!--<p class="field">
|
||||
<span>비만</span>
|
||||
</p>
|
||||
</p>-->
|
||||
<p class="name">
|
||||
<span class="name">박재우</span>
|
||||
대표원장 / <span>Chief Medical Director</span>
|
||||
@@ -45,14 +45,13 @@
|
||||
<span>Profile</span><br/>
|
||||
현) 메이드유의원 프랜차이즈 대표원장 <br/>
|
||||
현) 메이드유의원 강남본점 대표원장 <br/>
|
||||
현) 메이드유의원 비만센터 대표원장 <br/>
|
||||
대한미용외과학회 회원 <br/>
|
||||
대한미용성형레이저의학회 회원 <br/>
|
||||
대한비만치료학회 회원
|
||||
</p>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<!--<li>
|
||||
<img src="/image/web/profile2.png" alt="profile"/>
|
||||
<div class="text_box">
|
||||
<p class="field">
|
||||
@@ -74,7 +73,7 @@
|
||||
한국미용성형학회 회원
|
||||
</p>
|
||||
</div>
|
||||
</li>
|
||||
</li>-->
|
||||
<!-- <li> 2025.09.03 요구사항으로 인한 주석처리 byPJS
|
||||
<img src="/image/web/profile3.png" alt="profile"/>
|
||||
<div class="text_box">
|
||||
@@ -98,7 +97,7 @@
|
||||
</p>
|
||||
</div>
|
||||
</li> -->
|
||||
<li>
|
||||
<!--<li>
|
||||
<img src="/image/web/profile4.png" alt="profile"/>
|
||||
<div class="text_box">
|
||||
<p class="field">
|
||||
@@ -120,7 +119,7 @@
|
||||
대한미용성형레이저의학회 회원
|
||||
</p>
|
||||
</div>
|
||||
</li>
|
||||
</li>-->
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -3,10 +3,21 @@
|
||||
xmlns:th="http://www.thymeleaf.org"
|
||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
|
||||
<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>
|
||||
</head>
|
||||
|
||||
<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>
|
||||
|
||||
|
||||
@@ -5,8 +5,7 @@
|
||||
|
||||
<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="author" content="NTSOFT">
|
||||
<meta name="description" content={props.description} data-react-helmet="true" />
|
||||
<meta name="author" content="VARASOFT">
|
||||
|
||||
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
|
||||
<meta http-equiv="Cache-Control" content="No-Cache" />
|
||||
@@ -16,14 +15,13 @@
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE10">
|
||||
|
||||
<!-- sns미리보기 -->
|
||||
<meta name="description" content="다이어트약, 강남피부과,비만클리닉, 리쥬란힐러,신논현피부과,논현피부과,스컬트라,울쎄라,강남울쎄라,써마지,강남써마지,지방분해주사,윤곽주사">
|
||||
<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 property="og:title" content="메이드유의원 강남본점">
|
||||
<meta name="og:description" content="다이어트약, 강남피부과,비만클리닉, 리쥬란힐러,신논현피부과,논현피부과,스컬트라,울쎄라,강남울쎄라,써마지,강남써마지,지방분해주사,윤곽주사">
|
||||
|
||||
<!-- 사이트등록및소유확인 -->
|
||||
<meta name="naver-site-verification" content="" />
|
||||
<meta name="naver-site-verification" content="8720c03a4463520a0bd0979a3a743ff8ef0d8a03" />
|
||||
|
||||
<title>메이드유</title>
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
|
||||
<th:block th:fragment="layoutHeader">
|
||||
<th:block th:replace="/web/layout/layoutModal :: layoutModal"></th:block>
|
||||
<link rel="stylesheet" href="/css/web/quick_menu/quick_menu.css">
|
||||
<script>
|
||||
// 디바이스 감지 함수
|
||||
<th:block th:replace="/web/layout/layoutModal :: layoutModal"></th:block>
|
||||
<link rel="stylesheet" href="/css/web/quick_menu/quick_menu.css">
|
||||
<script>
|
||||
// 디바이스 감지 함수
|
||||
function isMobileDevice() {
|
||||
return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)
|
||||
|| window.innerWidth <= 768;
|
||||
@@ -26,8 +26,8 @@
|
||||
}
|
||||
}
|
||||
|
||||
function moveDietCenter(){
|
||||
window.location.href="https://diet.madeu.co.kr/index";
|
||||
function moveDietCenter() {
|
||||
window.location.href = "https://diet.madeu.co.kr/index";
|
||||
}
|
||||
// 모바일 여부 확인 함수
|
||||
function isMobile() {
|
||||
@@ -52,12 +52,18 @@
|
||||
quickMenu.style.display = '';
|
||||
}
|
||||
}
|
||||
function moveEvent() {
|
||||
window.location.href = "https://petit.madeu.co.kr/webevent/selectListWebEventIntro.do";
|
||||
}
|
||||
function moveReview() {
|
||||
window.location.href = "https://petit.madeu.co.kr/webreview/selectListProcedureReviewIntro.do";
|
||||
}
|
||||
|
||||
// 페이지 로드와 리사이즈 이벤트 연결
|
||||
window.addEventListener('load', toggleQuickMenu);
|
||||
window.addEventListener('resize', toggleQuickMenu);
|
||||
</script>
|
||||
<header>
|
||||
</script>
|
||||
<header>
|
||||
|
||||
<div class="inner_wrap">
|
||||
<button class="mb mbmenu" onClick="openNav()"></button>
|
||||
@@ -76,10 +82,15 @@
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
</header>
|
||||
<!-- 퀵메뉴 -->
|
||||
<div class="quick-menu-simple">
|
||||
|
||||
</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="moveDietCenter()">
|
||||
<img src="/image/quick_menu/diet_center.png" alt="다이어트센터">
|
||||
@@ -99,7 +110,8 @@
|
||||
<img src="/image/quick_menu/madeu_phone_number.png" alt="전화 상담">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="/js/web/layout/layoutHeader.js?ver=1"></script>
|
||||
</div>
|
||||
<script src="/js/web/layout/layoutHeader.js?ver=1"></script>
|
||||
</th:block>
|
||||
|
||||
</html>
|
||||
@@ -28,8 +28,7 @@
|
||||
.container {
|
||||
max-width: 1280px;
|
||||
width: 100%;
|
||||
height: calc(100vh - 300px); /* 헤더/푸터 공간 확보 */
|
||||
min-height: calc(100vh - 300px);
|
||||
height: 100vh; /* 헤더/푸터 공간 확보 */
|
||||
margin: 0 auto;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
|
||||
@@ -1,432 +1,21 @@
|
||||
<!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}">
|
||||
<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}">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
<th:block layout:fragment="layoutCss">
|
||||
<!-- Choices.js CSS -->
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/choices.js/10.2.0/choices.min.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>
|
||||
<!-- Choices.js 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}" />
|
||||
</th:block>
|
||||
|
||||
<th:block layout:fragment="layout_top_script">
|
||||
<script th:inline="javascript">
|
||||
let category_div_cd = [[${CATEGORY_DIV_CD}]];
|
||||
let category_no = [[${CATEGORY_NO}]];
|
||||
let post_no = [[${POST_NO}]];
|
||||
const CDN_URL = [[${@environment.getProperty('url.cdn')}]];
|
||||
</script>
|
||||
<script th:inline="javascript">
|
||||
let category_div_cd = [[${ CATEGORY_DIV_CD }]];
|
||||
let category_no = [[${ CATEGORY_NO }]];
|
||||
let post_no = [[${ POST_NO }]];
|
||||
const CDN_URL = [[${@environment.getProperty('url.cdn') }]];
|
||||
</script>
|
||||
</th:block>
|
||||
|
||||
<th:block layout:fragment="layoutContent">
|
||||
@@ -459,6 +48,8 @@ const CDN_URL = [[${@environment.getProperty('url.cdn')}]];
|
||||
</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="select-row">
|
||||
@@ -482,301 +73,9 @@ const CDN_URL = [[${@environment.getProperty('url.cdn')}]];
|
||||
</th:block>
|
||||
|
||||
<th:block layout:fragment="layoutContentScript">
|
||||
<!-- Choices.js JavaScript -->
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/choices.js/10.2.0/choices.min.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>
|
||||
<!-- Choices.js JavaScript -->
|
||||
<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>
|
||||
</th:block>
|
||||
|
||||
</html>
|
||||
@@ -1,407 +1,18 @@
|
||||
<!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}">
|
||||
<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">
|
||||
<style>
|
||||
* {
|
||||
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>
|
||||
<link rel="stylesheet" th:href="@{/css/web/webevent/webEventSelectList.css}" />
|
||||
</th:block>
|
||||
|
||||
<th:block layout:fragment="layout_top_script">
|
||||
<script th:inline="javascript">
|
||||
const CDN_URL = [[${@environment.getProperty('url.cdn')}]];
|
||||
</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="container">
|
||||
<!-- 상단 헤더 영역 -->
|
||||
<div class="header">
|
||||
<h1 class="page-title">이벤트 안내</h1>
|
||||
@@ -411,7 +22,6 @@ const CDN_URL = [[${@environment.getProperty('url.cdn')}]];
|
||||
<div class="content-wrapper">
|
||||
<!-- 좌측 사이드바 -->
|
||||
<aside class="sidebar">
|
||||
<div class="sidebar-header">이달의 이벤트</div>
|
||||
<ul class="category-list" id="category-list">
|
||||
<!-- 카테고리 JS로 렌더링 -->
|
||||
</ul>
|
||||
@@ -426,169 +36,21 @@ const CDN_URL = [[${@environment.getProperty('url.cdn')}]];
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 지난 이벤트 레이어 팝업 -->
|
||||
<div class="popup-overlay" id="expired-popup">
|
||||
<div class="popup-content">
|
||||
<div class="popup-icon">⏰</div>
|
||||
<div class="popup-title">지난 이벤트</div>
|
||||
<div class="popup-message">이 이벤트는 종료되었습니다.<br>다른 진행 중인 이벤트를 확인해 주세요.</div>
|
||||
<button class="popup-close-btn" onclick="eventManager.hideExpiredPopup()">확인</button>
|
||||
</div>
|
||||
</div>
|
||||
</th:block>
|
||||
|
||||
<th:block layout:fragment="layoutContentScript">
|
||||
<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>
|
||||
<script th:src="@{/js/web/webevent/webEventSelectList.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 href="https://cdn.jsdelivr.net/npm/quill@2.0.3/dist/quill.snow.css" rel="stylesheet" />
|
||||
<link rel="stylesheet" th:href="@{/css/web/webreview/procedureReviewSelect.css}" />
|
||||
</th:block>
|
||||
<th:block layout:fragment="layout_top_script">
|
||||
<script th:inline="javascript">
|
||||
const muProcedureReviewId = [[${ muProcedureReviewId }]];
|
||||
const CDN_URL = [[${@environment.getProperty('url.cdn') }]];
|
||||
</script>
|
||||
</th:block>
|
||||
<th:block layout:fragment="layoutContent">
|
||||
<div class="container">
|
||||
<div class="breadcrumb">
|
||||
<a href="/webreview/selectListProcedureReviewIntro.do">고객후기</a>
|
||||
<span>></span>
|
||||
<span id="breadcrumb-title">상세보기</span>
|
||||
</div>
|
||||
<article class="review-article">
|
||||
<div class="review-header">
|
||||
<h1 class="review-title" id="review-title"></h1>
|
||||
<div class="review-meta">
|
||||
<span class="review-date" id="review-date"></span>
|
||||
<span class="review-views">조회 <span id="review-views">0</span></span>
|
||||
</div>
|
||||
<div class="review-tags" id="review-tags"></div>
|
||||
</div>
|
||||
<div class="review-content" id="review-content">
|
||||
<div class="loading">게시글을 불러오는 중...</div>
|
||||
</div>
|
||||
</article>
|
||||
<div class="btn-area">
|
||||
<a href="/webreview/selectListProcedureReviewIntro.do" class="btn-list">목록으로</a>
|
||||
</div>
|
||||
</div>
|
||||
</th:block>
|
||||
<th:block layout:fragment="layoutContentScript">
|
||||
<script src="https://cdn.jsdelivr.net/npm/quill@2.0.3/dist/quill.js"></script>
|
||||
<script th:src="@{/js/web/webreview/procedureReviewSelect.js}"></script>
|
||||
</th:block>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,34 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
|
||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{/web/layout/layout}">
|
||||
<th:block layout:fragment="layoutCss">
|
||||
<link rel="stylesheet" th:href="@{/css/web/webreview/procedureReviewSelectList.css}" />
|
||||
</th:block>
|
||||
<th:block layout:fragment="layout_top_script">
|
||||
<script th:inline="javascript">
|
||||
const CDN_URL = [[${@environment.getProperty('url.cdn') }]];
|
||||
</script>
|
||||
</th:block>
|
||||
<th:block layout:fragment="layoutContent">
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<h1 class="page-title">고객후기</h1>
|
||||
<p class="page-subtitle">실제 고객님들의 생생한 후기를 확인하세요</p>
|
||||
</div>
|
||||
<div class="search-area">
|
||||
<div class="search-box">
|
||||
<input type="text" id="searchTitle" placeholder="제목으로 검색" />
|
||||
<button id="btnSearch" class="search-btn">검색</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="review-grid" id="review-grid">
|
||||
<div class="loading">고객후기를 불러오는 중...</div>
|
||||
</div>
|
||||
<div class="pagination-area" id="pagination-area"></div>
|
||||
</div>
|
||||
</th:block>
|
||||
<th:block layout:fragment="layoutContentScript">
|
||||
<script th:src="@{/js/web/webreview/procedureReviewSelectList.js}"></script>
|
||||
</th:block>
|
||||
|
||||
</html>
|
||||