서론
지난번엔 간단한 달력을 만들었습니다.
이번엔 Service가 제공한 data를 바탕으로 상호작용을 제한하고 추가적으로 시간표까지 출력하는 시스템입니다.
기초적인 달력은 지난번 포스팅을 했으므로, 기본적인 사항은 건너뛰도록 하겠습니다.
한번에 작성하려다 보니 내용이 너무 길어져서 달력과 시간표를 기준으로 상/하로 나누어서 포스팅하였습니다.
개발환경
- IDE : Eclipse
- 사용 언어 : HTML, JSP, Java script, SQL
- 사용 라이브러리 : JSTL, JSON
목차 |
1. 가정
2. 제약사항
3. 구조
ㄱ. HTML
ㄴ. Java script
4. 달력 구성
ㄱ. 지금 만들어진 달력이 현재 달력인지 확인
ㄴ. 요일입력에 내용 추가
ㄷ. 예약불가일자 처리 (1/2) - 요일생성 안
ㄹ. 예약불가일 예외처리
ㅁ. 예약가능일 클릭이벤트 추가
ㅂ. 예약불가일자 처리 (2/2) - 요일생성 밖
5. 지난달과 다음달 달력 출력
1. 가정
- 프로젝트 디자인 : MVC MODEL2
- 달력에 사용하는 table은 지난번 포스팅과 동일
- 예약의 꽉 찬 날도 Service에서 계산해 오름차순으로 정렬된 일자의 배열로 보내준 상태
<script type="text/javascript">
//JSTL을 사용해 jsva script의 array에 입력
var thisMonthFullDateList = new Array();
<c:forEach items="${thisMonthFullDateList}" var = "date">
thisMonthFullDateList.push(${date});
</c:forEach>
var nextMonthFullDateList = new Array();
<c:forEach items="${nextMonthFullDateList}" var = "date">
nextMonthFullDateList.push(${date});
</c:forEach>
//...
<script>
- 해당 시설의 정보는 service로부터 받아온 상태
<%
Dto_Share share = (Dto_Share)request.getAttribute("DETAIL");
%>
- 이용시 시간당 가격
int price = share.getPrice();
2. 제약사항
- 예약가능 요일 제한. 형식은 0000000 (순서대로 일월화수목금토 의 예약가능여부 표현, 0이면 예약불가, 1이면 예약가능)
char[] possibleDay = (share.getDayLimit()).toCharArray();
- 예약이 가능한 시점은 오늘 기준으로 내일부터 30일 이후까지
- 예약시 퐁당예약 불가능 ex) 9-10시예약과 11-12시를 동시 예약 불가
3. 구조
위에서 말한대로, 지난번 포스팅한 기본정인 사항은 제외하고 변경사항 및 추가사항을 기술하겠습니다.
ㄱ. HTML
//선택한 예약일시를 출력할 위치
<input id="selectedDate" name="selectedDate" value="" readonly="readonly">
//총 예약금액을 출력할 위치
<input id="totalPrice" name="totalPrice" value="" readonly="readonly">
ㄴ. Java script
//-------calendar--------------
var today = new Date();
var date = new Date();
//사용자가 클릭한 셀 객체 저장
var selectedCell;
//오늘 기준으로 불현하는 월. 일 객체
var realMonth = date.getMonth()+1;
var realToDay = date.getDate();
//사용자가 클릭한 일자의 월, 일 객체
var selectedMonth = null;
var selectedDate = null;
function prevCalendar(){...};
function nextCalendar(){...};
function buildCalendar(){...};
//대여자가 입력한 예약불가능 일자를 계산
function exchangeToPosibleDay(num);
//현재 사용자가 보는 달력이 이번달이면 0 리턴, 다음달이면 1 리턴
function thisMonth(todayMonth, dateMonth)
4. 달력 구성하기
위에서 말한대로, 지난번 포스팅한 기본정인 사항은 제외하고 변경사항 및 추가사항을 기술하겠습니다.
달력을 제작하는 buildCalendar()부터 시작하겠습니다.
function buildCalendar(){
row = null;
cnt = 0;
//...
ㄱ. 지금 만들어진 달력이 현재 달력인지 확인
nowMonth = today.getMonth()+1;
monthEquals = thisMonth(nowMonth, realMonth);
이번 달력은 비교가 굉장히 빈번하게 사용되므로, 선언하고 시작합니다.
thisMonth(todatMonth, dateMonth)
//이번달이면 0 리턴, 다음달이면 1 리턴
function thisMonth(todayMonth, dateMonth){
if (todayMonth*1 == dateMonth*1){
return 0;
}
return 1;
}
ㄴ. 요일입력에 내용 추가
for(i = 1; i <= lastDate.getDate(); i++){
noCount = 0;
etp = exchangeToPosibleDay(cnt)*1;
//...
}
noCount
- 예약을 못하는 제약사항에 해당되면 1씩 증가
- 예약불가능한 제약사항이 3가지나 되므로, 일괄적으로 예약불가 처리를 위해 상용
etp : exchangeToPosibleDay(cnt)*1의 결과
exchangeToPosibleDay(cnt)
//사용자가 입력한 예약불가능 일자와 대조하기 위해 0~7의 환형 계산구조
function exchangeToPosibleDay(num){
result = num % 7;
result -= 1;
if (result == -1) {
result = 6;
}
return result;
}
기능
- cnt를 매개변수로 넣어 현재 일이 '무슨 요일'인지 반환 (1: 일, 2: 월, 3:화, 4:수, 5:목, 6:금, 7:토)
result에서 1 빼고 연산하는 이유
- 이후 배열의 인덱스로 사용해 해당값을 조회해야 함. 배열의 인덱스는 0부터 시작이기 때문
i(일수)대신 cnt를 사용하는 이유
- i와 cnt는 같이 1씩 증가하지만 시작이 다름. i(요일)의 시작은 월의 첫 날, cnt의 시작은 첫 행 첫번째 셀
- i자체로는 '무슨 요일'인지 파악할 수 없음
- cnt로 i(일)이 '무슨'요일인지 7로 나머지연산을 해서 알 수 있음
ㄷ. 예약불가일자 분류 (1/2) - 요일생성 안
if (nowMonth == realMonth && i <= realToDay) {
noCount +=1;
} else if (nowMonth > realMonth && i > realToDay) {
noCount +=1;
} else if (possibleDay[etp] == 0){
noCount +=1;
}
예약불가일자 분류를 2번에 나눠서 하는 이유
- 예약이 가득찬 날을 배열로 보유하고 있으므로, 날마다 탐색하는것은 비효율적임
- for문 종료 후 예약이 가득찬 날의 배열을 순차탐색해서 해당 일자의 id를 가진 cell을 핸들링 하는것이 더 효율적
조건들의 의미
- 조건1 : 이번달이고 오늘을 포함한 지난날
- 조건2 : 다음달이고 오늘보다 일이 높은 수일때
- 조건3 : 해당 일이 예약불가 요일일 경우
참고사항
- etp의 값 범위 : 0~6 (0일 1월 2화 3수 4목 5금 6토)
- possibleDay : 7자리의 2진수로 이루어지고, 왼쪽부터 일월화수목금을 표현
ㄹ. 예약불가일 예외처리
if (noCount > 0){
cell.style.backgroundColor = "#E0E0E0";
cell.innerHTML = "<font color='#C6C6C6' >" + i + "</font>";
} else {
cell.onclick = function(){
//...
}
- noCount가 1이상이면 배경색을 회색으로, 글자색도 연한 검정으로 변경
- else구문에 cell의 클릭이벤트 함수를 작성함으로써 noCount가 0일경우에만 클릭이벤트가 생성
ㅁ. 예약가능일 클릭이벤트 추가
a. 타임테이블 초기화
selectedTimeAndTotalPriceInit();
클릭마다 초기화하는 이유
- 다른날을 클릭해도 테이블이 남아있으면 시간표를 생성해도 밑에 쌓임
b. 선택된 월, 일을 전역변수에 저장
selectedMonth = today.getMonth() + 1;
selectedDate = this.getAttribute('id');
선택된 월 , 일을 저장하는 이유
- 시간표에서 사용하기 때문
c. 클릭한 셀을 전역변수에 저장후 색 변경 및 기존 선택된 샐의 색 복구
//선택된 셀 색 변화
if(selectedCell != null){
selectedCell.bgColor = "#FFFFFF";
}
selectedCell = this;
this.bgColor = "#fbedaa";
ㅂ. 예약불가일자 분류 (2/2) - 요일생성 밖
fullDate = [];
if(monthEquals == 0){
fullDate = thisMonthFullDateList;
}else {
fullDate = nextMonthFullDateList;;
}
for (var i = 0; i < fullDate.length; i++){
cell = document.getElementById(fullDate[i]);
cell.style.backgroundColor = "#E0E0E0";
cell.style.color = '#C6C6C6';
cell.onclick = function(){};
}
조건문 의미
- 위에서 구해뒀던 monthEquals를 사용해 달에 알맞은 정보를 담은 Array를 사용하기 위함
굳이 나눈 이유
- 요일을 29~31개 만들때마다 조회하는거 보단 이게 효율적
예약불가 처리방법
- fullDate는 지금 만드는 달의 날짜중 예약이 꽉 찬 날을 int로 보유함
- fullDate를 순차탐색해 해당하는 날짜의 id를 가진 cell을 호출
- 배경색과 글자색을 예약불가일과 동일하게 변경
- 클릭이벤트 함수를 빈 함수로 덮어씌워 클릭이벤트를 초기화
5. 지난달과 다음달 달력 출력
//전달 달력
function prevCalendar(){
if (today.getMonth() < realMonth){
alert("예약은 금일기준 다음날부터 30일 이후까지만 가능합니다.");
return false;
}
today = new Date(today.getFullYear(), today.getMonth()-1, today.getDate());
buildCalendar();
}
//다음달 달력
function nextCalendar(){
if(today.getMonth()+1 == (realMonth + 1)){
alert("예약은 금일기준 다음날부터 30일 이후까지만 가능합니다.");
return false;
}
today = new Date(today.getFullYear(), today.getMonth()+1, today.getDate());
buildCalendar();
}
- 제약사항중 오늘을 포함 이전 및 오늘기준 +30일 이후는 예약 못하므로, 전달과 다다음달은 이동 못하도록 제한
전체 코드 보기
Command
public class ReservationCommand implements SCommand {
@Override
public void execute(SqlSession sqlSession, Model model, HttpSession httpSession) {
Map<String, Object> map = model.asMap();
HttpServletRequest request = (HttpServletRequest) map.get("request");
int sNo = Integer.parseInt(request.getParameter("sNo"));
Dto_Share detail = ReservationInfo.detail;
//총 이용 가능한 시간
int totalTime = detail.getEndTime() - detail.getStartTime();
DecimalFormat df = new DecimalFormat("00");
Calendar currentCalendar = Calendar.getInstance();
int month = Integer.parseInt(df.format(currentCalendar.get(Calendar.MONTH) + 1));
//dto를 이번달과 다음달로 분류
ArrayList<Dto_Reservation_rental> thisMonthDtos = new ArrayList<Dto_Reservation_rental>();
ArrayList<Dto_Reservation_rental> nextMonthDtos = new ArrayList<Dto_Reservation_rental>();
// 예약일자,Dto_Reservation_rental 쌍의 LinkedHashMap : 순서를 보장한다. 정렬후 사용하므로 순서 보장이 되는쪽이 효율
LinkedHashMap<Integer, Dto_Refine_rental> thisMonthResMap =
new LinkedHashMap<Integer, Dto_Refine_rental>();
LinkedHashMap<Integer, Dto_Refine_rental> nextMonthResMap =
new LinkedHashMap<Integer, Dto_Refine_rental>();
//map을 jsonArray로 변환
JSONArray thisMonthResData = new JSONArray();
JSONArray nextMonthResData = new JSONArray();
//이용시간이 꽉 찬 경우의 일자를 따로 저장한다.
ArrayList<Integer> thisMonthFullDate = new ArrayList<Integer>();
ArrayList<Integer> nextMonthFullDate = new ArrayList<Integer>();
// 성공적으로 로드를 못할 때도 존재하니 no 일치하는지 검사
if (sNo == detail.getNo()) {
detail.printAll();
Dao_Reservation dao = sqlSession.getMapper(Dao_Reservation.class);
ArrayList<Dto_Reservation_rental> preDtos = dao.refineShares(detail.getPlace_no());
ArrayList<Dto_Reservation_rental> dtos = new ArrayList<Dto_Reservation_rental>();
for (Dto_Reservation_rental preDto : preDtos) {
Timestamp checkInDate = preDto.getCheckInDate();
System.out.println("checkInDate : " + checkInDate);
int startTime = preDto.getStartTime();
int endTime = preDto.getEndTime();
Calendar calendar = Calendar.getInstance();
calendar.setTime(checkInDate);
int tMonth = calendar.get(Calendar.MONTH) + 1;
int tDate = calendar.get(Calendar.DATE);
int tUsingTime = endTime - startTime;
Dto_Reservation_rental uDto = new Dto_Reservation_rental(tMonth, tDate, startTime, tUsingTime);
System.out.println(month + " / " + tDate + " : " + startTime + " + " + tUsingTime);
dtos.add(uDto);
}
//dto를 이번달과 다음달로 분류
for(Dto_Reservation_rental dto : dtos) {
System.out.println("이번달 : " + month + " dto의 달 : " + dto.getMonth());
if (dto.getMonth() == month) {
thisMonthDtos.add(dto);
} else {
nextMonthDtos.add(dto);
}
}
//각 dtos에서 예약일자 추출해 하나의 날자로 통
for (Dto_Reservation_rental dto : thisMonthDtos) {
Dto_Refine_rental refineData;
//예약일자가 map에 존재하지 않는다면 추가
if (thisMonthResMap.containsKey(dto.getDate()) == false) {
//map에 넣을 dto 생성
refineData = new Dto_Refine_rental();
} else {
//이 경우는 이미 map에 존재하므로, 불러온다
refineData = thisMonthResMap.get(dto.getDate());
}
refineData.insertData(detail.getStartTime(), dto.getStartTime(), dto.getUsingTime());
//해당 키값의 벨류를 갱신시켜준다. (put은 갱신 및 추가 둘다 사용 가능
thisMonthResMap.put(dto.getDate(), refineData);
}
for (Dto_Reservation_rental dto : nextMonthDtos) {
Dto_Refine_rental refineData;
//예약일자가 map에 존재하지 않는다면 추가
if (nextMonthResMap.containsKey(dto.getDate()) == false) {
//map에 넣을 dto 생성
refineData = new Dto_Refine_rental();
} else {
//이 경우는 이미 map에 존재하므로, 불러온다
refineData = nextMonthResMap.get(dto.getDate());
}
refineData.insertData(detail.getStartTime(), dto.getStartTime(), dto.getUsingTime());
//해당 키값의 벨류를 갱신시켜준다. (put은 갱신 및 추가 둘다 사용 가능
nextMonthResMap.put(dto.getDate(), refineData);
}
//map에서 json으로 변환
for(Map.Entry<Integer, Dto_Refine_rental> refineData :thisMonthResMap.entrySet()) {
Dto_Refine_rental dto = refineData.getValue();
JSONObject jsonObject = new JSONObject();
jsonObject.put("date", refineData.getKey());
jsonObject.put("startNum", dto.getStartNum());
jsonObject.put("shareTime", dto.getShareTime());
jsonObject.put("totalShareTime", dto.getTotalShareTime());
thisMonthResData.add(jsonObject);
if(totalTime <= dto.getTotalShareTime()) {
System.out.println("java 꽉 찬날 : " + refineData.getKey());
thisMonthFullDate.add(refineData.getKey());
}
}
for(Map.Entry<Integer, Dto_Refine_rental> refineData :nextMonthResMap.entrySet()) {
Dto_Refine_rental dto = refineData.getValue();
JSONObject jsonObject = new JSONObject();
jsonObject.put("date", refineData.getKey());
jsonObject.put("startNum", dto.getStartNum());
jsonObject.put("shareTime", dto.getShareTime());
jsonObject.put("totalShareTime", dto.getTotalShareTime());
nextMonthResData.add(jsonObject);
if(totalTime <= dto.getTotalShareTime()) {
System.out.println("java 꽉 찬날 : " + refineData.getKey());
nextMonthFullDate.add(refineData.getKey());
}
}
// share-detail 정보 dto로 담아 전송
model.addAttribute("DETAIL", detail);
// dto를 이번달과 다음달로 나눠서 전송
model.addAttribute("thisMonthResData", thisMonthResData);
model.addAttribute("nextMonthResData", nextMonthResData);
Integer[] thisMonthFullDateList = thisMonthFullDate.toArray(new Integer[thisMonthFullDate.size()]);
Integer[] nextMonthFullDateList = nextMonthFullDate.toArray(new Integer[nextMonthFullDate.size()]);
model.addAttribute("thisMonthFullDateList", thisMonthFullDateList);
model.addAttribute("nextMonthFullDateList", nextMonthFullDateList);
model.addAttribute("error", 0);
System.out.println("place no이 동일하므로 다음작업을 수행합니다.");
} else {
System.out.println("시스템 오류. 데이터를 로드하는데 문제가 발생했습니다.");
//error 전송
model.addAttribute("error", 1);
}
}
}
view
<%@page import="com.team4.ysms.common.LoginedUserInfo"%>
<%@page import="org.json.simple.JSONArray"%>
<%@page import="com.team4.ysms.dto.Dto_Refine_rental"%>
<%@page import="com.team4.ysms.dto.Dto_Share"%>
<%@page import="java.util.ArrayList"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri = "http://java.sun.com/jsp/jstl/core" prefix = "c" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<link rel="preconnect" href="https://fonts.gstatic.com">
<link href="https://fonts.googleapis.com/css2?family=Nanum+Gothic:wght@400;700;800&display=swap" rel="stylesheet">
<link rel="stylesheet" href="/ysms/resources/css/reservation.css" type="text/css">
<title>Reservation : ${DETAIL.title}</title>
<style>
#reservation_share{
margin:50px;
width:970px;
border-collapse:collapse;
color: #505050;
/* border: 1px solid #f0f0f0; */
}
#reservation_share td.top{
padding-bottom: 10px;
font-weight:700; font-size:25px;
}
#reservation_share td.title{
padding-left: 15px;
width:110px;
height: 90px;
font-weight:700;
font-size:20px;
border-bottom: 1px solid #dcdcdc;
background-color: #fbedaa;
}
#reservation_share td.content{
font-size:19px;
width:320px;
padding-left:20px;
border-bottom: 1px solid #dcdcdc;
}
#reservation_user{
margin:50px;
width:600px;
border-collapse:collapse;
color: #505050;
/* border: 1px solid #dcdcdc; */
}
#reservation_user td.top{
padding-bottom: 20px;
font-weight:700; font-size:25px;
}
#reservation_user td.title{
padding : 15px;
font-weight:700;
font-size:20px;
}
#reservation_user td.content{
font-size:19px;
width:450px;
padding-left:20px;
}
#reservation_time{
margin:50px;
width:600px;
border-collapse:collapse;
color: #505050;
/* border: 1px solid #dcdcdc; */
}
#reservation_time td.top{
padding-bottom: 20px;
font-weight:700; font-size:25px;
}
#reservation_time td.content{
padding-bottom: 50px;
}
#calendar{margin-bottom:50px; padding: 10px; width:250px; color: #505050; border: 1px solid #dcdcdc;}
#calendar td{padding:10px; }
#timeTable{margin-bottom:50px; padding: 5px; width:200px; color: #505050;}
#timeTable td{padding:8px; }
#selectedDate{width: 200px; height: 25px; padding: 10px;
color: #505050; font-size:17px; background-color: #fff; border: 1px solid #dcdcdc; }
#selectedTime{width: 200px; height: 25px; padding: 10px;
color: #505050; font-size:17px; background-color: #fff; border: 1px solid #dcdcdc; }
#totalPrice{width: 200px; height: 25px; padding: 10px;
color: #505050; font-size:17px; background-color: #fff; border: 1px solid #dcdcdc; }
#btn_submit{
margin: 0;
padding: 20px;
text-align: center;
text-decoration: none;
font-size: 20px; color:#fff;
background-color: #ace2f9;
font-weight:700;
border: none;
/* border-radius: 10px; */
display: inline-block;
width: 300px;
}
#btn_submit:hover{
margin: 0;
padding: 20px;
text-align: center;
text-decoration: none;
font-size: 20px; color:#ace2f9;
background-color: #fff;
font-weight:700;
border: 1px solid #ace2f9;
/* border-radius: 10px; */
display: inline-block;
width: 300px;
}
</style>
</head>
<%
if ((Integer)request.getAttribute("error") == 1){
out.println("<script>alert('오류발생1!!');history.back();</script>");
}
//유저정보 획득
String userName = LoginedUserInfo.name;
String userPhone = LoginedUserInfo.phone;
String userEmail = LoginedUserInfo.email;
//share detail data
Dto_Share share = (Dto_Share)request.getAttribute("DETAIL");
//JSON 형식으로 달의 날자별 예약현황을 전송받음
JSONArray thisMonthResData = (JSONArray)request.getAttribute("thisMonthResData");
JSONArray nextMonthResData = (JSONArray)request.getAttribute("nextMonthResData");
//예약가능 요일 (일~월, 가능0 불가능1)
char[] possibleDay = (share.getDayLimit()).toCharArray();
//예약가능 시간 (start time~end time) end - start = 이용가능시
int startTime = share.getStartTime();
int endTime = share.getEndTime();
//총 이용 가능 시간
int totalUsingTime = endTime - startTime;
//시간당 가격
int price = share.getPrice();
%>
<script src="http://code.jquery.com/jquery-latest.min.js"></script>
<script type="text/javascript">
//예약이 가득찬 날들의 배열
var thisMonthFullDateList = new Array();
<c:forEach items="${thisMonthFullDateList}" var = "date">
thisMonthFullDateList.push(${date});
</c:forEach>
var nextMonthFullDateList = new Array();
<c:forEach items="${nextMonthFullDateList}" var = "date">
nextMonthFullDateList.push(${date});
</c:forEach>
//---------------- calendar --------------------------
//date객체 획득. 가변
var today = new Date();
//today 보조. 고정
var date = new Date();
//선택되있던 셀 객체 저장
var selectedCell;
//오늘에 해당하는 월
var realMonth = date.getMonth()+1;
var realToDay = date.getDate()
//선택된 월, 일
var selectedMonth = null;
var selectedDate = null;
//예약가능 요일 계산해 배열 (일~월, 가능0 불가능1)
const possibleDay = "<%=possibleDay%>";
//전달 달력
function prevCalendar(){
if (today.getMonth() < realMonth){
alert("예약은 금일기준 다음날부터 30일 이후까지만 가능합니다.");
return false;
}
today = new Date(today.getFullYear(), today.getMonth()-1, today.getDate());
buildCalendar();
}
//다음달 달력
function nextCalendar(){
if(today.getMonth()+1 == (realMonth + 1)){
alert("예약은 금일기준 다음날부터 30일 이후까지만 가능합니다.");
return false;
}
today = new Date(today.getFullYear(), today.getMonth()+1, today.getDate());
buildCalendar();
}
//달력 제작 (이번달 기준)
function buildCalendar(){
row = null;
cnt = 0;
firstDate = new Date(today.getFullYear(), today.getMonth(), 1);
lastDate = new Date(today.getFullYear(), today.getMonth()+1, 0);
//현재 참조중인 월
nowMonth = today.getMonth()+1;
//이번달이면 0, 다음달이면 1 리턴
monthEquals = thisMonth(nowMonth, realMonth);
//달력 객체
var calendarTable = document.getElementById("calendar");
//달력의 타이틀 객체 획득
var calendarTableTitle = document.getElementById("calendarTitle");
//타이틀 수정
calendarTableTitle.innerHTML = today.getFullYear()+"년"+(today.getMonth()+1)+"월";
//테이블 초기화
while(calendarTable.rows.length > 2){
calendarTable.deleteRow(calendarTable.rows.length -1);
}
//셀 입력을 위해 테이블 개행
row = calendarTable.insertRow();
//달의 첫 날 전까지 빈 셀 생성
for(i = 0; i < firstDate.getDay(); i++){
cell = row.insertCell();
cnt += 1;
}
//요일 입력 (셀 생성)
for(i = 1; i <= lastDate.getDate(); i++){
//예약하지 못하는 조건일경우 +1씩 되므로, noCount가 0일 시에만 클릭함수를 적용
noCount = 0;
cell = row.insertCell();
//cell에 id 부여
cell.setAttribute('id', i);
cell.innerHTML = i;
//cell.innerHTML = '<label onclick="prevCalendar()">' + i + '</label>';
cell.align = "center";
//셀 생성 후 count 증가
cnt += 1;
//cnt % 7 == 1이면 일요일이므로 빨갛게
if (cnt % 7 == 1) {
cell.innerHTML = "<font color=#F79DC2>" + i + "</font>";
}
//일주일 입력 완료시 개행
if (cnt % 7 == 0){
//cnt % 7 == 0이면 토요일이므로 파랗게
cell.innerHTML = "<font color=skyblue>" + i + "</font>";
row = calendar.insertRow();
}
//예약불가일 색상변경 (오늘 이전 또는 30일 이후) 및 사용자가 직접 지정한 경우
etp = exchangeToPosibleDay(cnt)*1;
if (nowMonth == realMonth && i <= realToDay) {
noCount +=1;
} else if (nowMonth > realMonth && i > realToDay) {
noCount +=1;
} else if (possibleDay[etp] == 1){
noCount +=1;
}
if (noCount > 0){
cell.style.backgroundColor = "#E0E0E0";
cell.innerHTML = "<font color='#C6C6C6' >" + i + "</font>";
} else {
cell.onclick = function(){
selectedTimeAndTotalPriceInit();
//선택된 날의 연, 월, 일 계산 (일자의 경우 id속성 참조)
clickedYear = today.getFullYear();
clickedMonth = (1 + today.getMonth());
clickedMonth = clickedMonth >= 10 ? clickedMonth : '0' + clickedMonth;
clickedDate = this.getAttribute('id');
clickedDate = clickedDate >= 10 ? clickedDate : '0' + clickedDate;
clickedYMD = clickedYear + "-" + clickedMonth + "-" + clickedDate;
//하단에 예약일시 표시
inputField = document.getElementById("selectedDate");
inputField.value = clickedYMD;
//선택된 월, 일 변수 저장
selectedMonth = today.getMonth() + 1;
selectedDate = this.getAttribute('id');
//선택된 셀 색 변화
if(selectedCell != null){
selectedCell.bgColor = "#FFFFFF";
}
selectedCell = this;
this.bgColor = "#fbedaa";
//time table 생성
timeTableMaker(today.getMonth() + 1,this.getAttribute('id'));
}
}
}
//예약이 가득찬 날인 경우 cell 비활성화 및 색상 변rud
checkMonth = thisMonth(nowMonth, realMonth);
fullDate = [];
if(checkMonth == 0){
fullDate = thisMonthFullDateList;
}
if(checkMonth == 1){
fullDate = nextMonthFullDateList;;
}
for (var i = 0; i < fullDate.length; i++){
console.log("꽉 찬날 : " + fullDate[i]);
cell = document.getElementById(fullDate[i]);
console.log("꽉 찬날 : " + cell.innerHTML);
cell.style.backgroundColor = "#E0E0E0";
cell.style.color = '#C6C6C6';
cell.onclick = function(){};
}
//달의 마지막날 뒤 행의 빈 공간을 셀로 채우기
if(cnt % 7 != 0){
for(i = 0; i < 7 - (cnt % 7); i++){
cell = row.insertCell();
}
}
}
//사용자가 입력한 예약불가능 일자와 대조하기 위해 0~7의 환형 계산구조
function exchangeToPosibleDay(num){
result = num % 7;
result -= 1;
if (result == -1) {
result = 6;
}
return result;
}
//이번달이면 0 리턴, 다음달이면 1 리턴
function thisMonth(todayMonth, dateMonth){
console.log("todayMonth : " + todayMonth + ", dateMonth : " + dateMonth);
if (todayMonth*1 == dateMonth*1){
console.log("이번달 이구요")
return 0;
}
console.log("다음달 이구요")
return 1;
}
// ---------------- time table --------------------------
var price = "<%=price%>";
var startTime = "<%=startTime%>";
var endTime = "<%=endTime%>";
//선택된 시간중 가장 빠른/늦은 시간;
var selectedFirstTime = 24*1;
var selectedFinalTime = 0*1;
//예약시간표를 만들 table객체 획득
function timeTableMaker(selectedMonth, selectedDate){
row = null
month = selectedMonth;
date = selectedDate;
var timeTable = document.getElementById("timeTable");
//테이블 초기화
while(timeTable.rows.length > 0){
timeTable.deleteRow(timeTable.rows.length-1);
}
for (i = 0; i < endTime - startTime; i++){
//곱해서 숫자타입으로 변환
cellTime = startTime*1 + i;
cellStartTimeText = cellTime + ":00";
cellEndTimeText = (cellTime + 1) + ":00";
inputCellText = cellStartTimeText + " ~ " + cellEndTimeText;
//셀 입력을 위해 테이블 개행
row = timeTable.insertRow();
//해당 row의 셀 생성
cell = row.insertCell();
//cell에 id 부여
cell.setAttribute('id', cellTime);
//셀에 입력
cell.innerHTML = inputCellText;
//selectedCell.bgColor = "#FFFFFF";
//cell.innerHTML = "<font color='#C6C6C6' >" + inputCellText + "</font>";
//클릭이벤
cell.onclick = function(){
cellTime = this.getAttribute('id');
cellTime = cellTime*1;
console.log("first : " + selectedFirstTime + ", selectedFinalTime : " + selectedFinalTime + ", selected : " + cellTime);
//예약일시 입력처리
if (selectedFirstTime != 24 && selectedFinalTime != 0){
if(cellTime < selectedFirstTime - 1){
alert("연속한 시간만 예약가능합니다.");
return false;
}
if (cellTime > selectedFinalTime + 1){
alert("연속한 시간만 예약가능합니다.");
console.log(cellTime + ">" + selectedFinalTime + 1)
return false;
}
}
this.bgColor = "#fbedaa";
if (cellTime < selectedFirstTime) {
selectedFirstTime = cellTime
}
if (cellTime > selectedFinalTime) {
selectedFinalTime = cellTime
}
//하단의 예약일시에 시간 표시
resTime = selectedFirstTime + ":00 ~ " + (selectedFinalTime + 1) + ":00";
resTimeForm = document.getElementById("selectedTime");
resTimeForm.value = resTime;
//하단의 결제정보에 가격정보 표시
useTime = (selectedFinalTime + 1) - selectedFirstTime;
useTimeForm = document.getElementById("totalPrice");
useTimeForm.value = useTime * price;
}
}
//JSON으로 테이블 td 핸들링
//이번달 0 다음달 1
nowMonth = today.getMonth()+1;
checkMonth = thisMonth(nowMonth, realMonth);
var json = [];
if(checkMonth == 0){
json = <%=thisMonthResData%>;
} else {
json = <%=nextMonthResData%>;
}
for(i = 0; i < Object.keys(json).length; i++){
if (date == json[i].date){
jsonObject = json[i];
for(j = 0; j < jsonObject.startNum.length; j++){
startNum = jsonObject.startNum[j];
shareTime = jsonObject.shareTime[j];
console.log("startNum: " + startNum + ", shareTime : " + shareTime);
for(k = startNum; k < startNum*1 + shareTime; k++){
cell = timeTable.rows[k].cells[0];
cell.style.backgroundColor = "#E0E0E0";
cell.style.color = '#C6C6C6';
cell.onclick = function(){};
}
}
}
}
}
//시간효 초기화
function tableinit(){
timeTableMaker(selectedMonth, selectedDate);
selectedTimeAndTotalPriceInit();
buildCalendar();
}
//날자 클릭시 예약시간 및 결제정보 초기화
function selectedTimeAndTotalPriceInit(){
resDateForm = document.getElementById("selectedDate");
resTimeForm = document.getElementById("selectedTime");
resTimeForm.value = "";
resDateForm.value = "";
useTimeForm = document.getElementById("totalPrice");
useTimeForm.value = "";
selectedFirstTime = 24*1;
selectedFinalTime = 0*1;
}
//체크박스 이벤트
function checkboxEvent(checkbox){
nameForm = document.getElementById("userName");
phoneForm = document.getElementById("userPhone");
emailForm = document.getElementById("userEmail");
userName = "<%=userName%>";
userPhone = "<%=userPhone%>";
userEmail = "<%=userEmail%>";
if(checkbox.checked == true){
nameForm.value = userName;
phoneForm.value = userPhone;
emailForm.value = userEmail;
} else {
nameForm.value = "";
phoneForm.value = "";
emailForm.value = "";
}
}
function submitRes(){
arr = new Array();
nameForm = document.getElementById("userName");
phoneForm = document.getElementById("userPhone");
emailForm = document.getElementById("userEmail");
capacityForm = document.getElementById("capacity");
resTimeForm = document.getElementById("selectedTime");
selectedDateFrom = document.getElementById("selectedDate");
selectedTimeForm = document.getElementById("selectedTime");
totalPriceForm = document.getElementById("totalPrice");
arr.push(nameForm);
arr.push(phoneForm);
arr.push(emailForm);
arr.push(resTimeForm);
arr.push(selectedDateFrom);
arr.push(selectedTimeForm);
arr.push(totalPriceForm);
for (i = 0; i < arr.length; i++){
item = arr[i];
if(item.value == "" ){
alert("미기입된 정보가 있습니다.");
item.focus();
return false;
}
}
if ( ${DETAIL.capacity} < capacityForm.value){
alert("인원수가 초과되었습니다.");
capacityForm.focus();
return false;
}
popUp = window.open("payment", "payment");
form = document.paymentForm
form.action = "payment";
form.target = "payment";
form.submit();
}
</script>
<body>
<%@ include file="header.jsp" %>
<div class="mainBox">
<div class="contentBox">
<div class="textLeft"><span style="color: #505050; font-size:40px; font-weight:700">예약하기</span>
<div class="underline"></div></div>
<form action="payment" method="post" name="paymentForm">
<table id="reservation_share" align="center">
<tr>
<td class="top" colspan="3" align="left">공간명 ${DETAIL.title}</td>
</tr>
<tr>
<td rowspan="3">
<div class="share"><img class="sharePhoto" src="${DETAIL.filePath }"/></div></td>
<td class="title" align="left" style="border-top:1px solid #dcdcdc;"> 공간 유형 </td>
<c:if test="${DETAIL.category == 1 }"><td class="content" align="left" style="border-top:1px solid #dcdcdc;">휴식</td></c:if>
<c:if test="${DETAIL.category == 2 }"><td class="content" align="left" style="border-top:1px solid #dcdcdc;">파티</td></c:if>
<c:if test="${DETAIL.category == 3 }"><td class="content" align="left" style="border-top:1px solid #dcdcdc;">공부</td></c:if>
<c:if test="${DETAIL.category == 4 }"><td class="content" align="left" style="border-top:1px solid #dcdcdc;">회의</td></c:if>
</tr>
<tr>
<td class="title" align="left">최대 인원</td>
<td class="content" align="left">1 ~ ${DETAIL.capacity}명</td>
</tr>
<tr>
<td class="title" align="left">주소</td>
<td class="content" align="left">${DETAIL.address1}<br>${DETAIL.address2}</td>
</tr>
</table>
<table id="reservation_user">
<tr>
<input type="hidden" name="productName" value="${DETAIL.title}"></input>
<input type="hidden" name="placeNo" value="${DETAIL.place_no}"></input>
<td class="top" align="left">예약자 정보</td>
<td class="content" align="right">
<input type="checkbox" onclick="checkboxEvent(this)">계정과 동일</td>
</tr>
<tr>
<td class="title" align="right">예약자</td>
<td class="content" align="left"> <input type="text" id="userName" name="userName" size="20"> </td>
</tr>
<tr>
<td class="title" align="right">전화번호</td>
<td class="content" align="left"> <input type="text" id="userPhone" name="userPhone" size="20"> </td>
</tr>
<tr>
<td class="title" align="right">이메일</td>
<td class="content" align="left"> <input type="text" id="userEmail" name="userEmail" size="20"> </td>
</tr>
<tr>
<td class="title" align="right">인원수</td>
<td class="content" align="left"> <input type="text" id="capacity" name="capacity" size="20"> </td>
</tr>
</table>
<table id="reservation_time">
<tr>
<td class="top" align="left">시간선택</td>
<td class="top" align="right"><button class="btnTime" type="button" onclick="tableinit()">초기화</button></td>
</tr>
<tr>
<td>
<table id="calendar">
<tr>
<td align="center"><label onclick="prevCalendar()"> ◀ </label></td>
<td colspan="5" align="center" id="calendarTitle">yyyy년 m월</td>
<td align="center"><label onclick="nextCalendar()"> ▶ </label></td>
</tr>
<tr>
<td align="center"><font color ="#F79DC2">일</td>
<td align="center">월</td>
<td align="center">화</td>
<td align="center">수</td>
<td align="center">목</td>
<td align="center">금</td>
<td align="center"><font color ="skyblue">토</td>
</tr>
</table>
</td>
<td>
<table id = "timeTable"> </table>
</td>
</tr>
<tr>
<td class="top" align="left" colspan="2">예약일시</td>
</tr>
<tr>
<td class="content" colspan="2" align="left">
<input id="selectedDate" style="border:none; width:100px" name="selectedDate" value="" readonly="readonly" ></input>
<input id="selectedTime" style="border:none" name="selectedTime" value="" readonly="readonly"></input>
</td>
</tr>
<tr>
<td class="top" align="left">결제정보</td>
</tr>
<tr>
<td class="content" align="left" colspan="2">
<input id="totalPrice" style="border:none; text-align:right; width:100px" name="totalPrice" value="" readonly="readonly">원</input>
</td>
</tr>
<tr>
<td class="content" align="left" colspan="2">
<input id="btn_submit" type="button" value="결제하기" onclick="submitRes()"></td>
<tr>
</table>
</form>
</div>
</div>
<script type="text/javascript">buildCalendar();</script>
<%@ include file="footer.jsp" %>
</body>
</html>
'IDE & Framework > 분류중' 카테고리의 다른 글
JS 상호작용되는 달력 만들기 (5) - 예약달력 (하) (0) | 2021.06.01 |
---|---|
JS 상호작용되는 달력 만들기 (4) - 예약달력 (중) (0) | 2021.06.01 |
JS 상호작용되는 달력 만들기 (2) - 날짜 검색 달력 (1) | 2021.05.31 |
JS 상호작용되는 달력 만들기 (1) - 시작하며 (1) | 2021.05.31 |
JSP 이미지CRUD가 가능한 페이징된 게시판 구현 (0) | 2021.05.31 |