댓글 검색 목록

[php] PHP MySQL을 이용한 3 단계 예약 시스템

페이지 정보

작성자 운영자 작성일 20-04-18 12:19 조회 1,150 댓글 0

온라인 예약 


간단한 PHP 예약 시스템을 만드는 방법에 대한 자습서에 오신 것을 환영합니다. 

그래서 당신은 서비스를 제공하고 온라인 예약을 위해 개방하고 싶습니까? 

아니면 온라인으로 대여 가능한 방을 열고 싶습니까? 두려워하지 마십시오 –이 안내서는 예약 시스템을 만드는 방법에 대한 단계를 안내합니다.


ⓘ이 튜토리얼의 시작 부분에 모든 소스 코드가 포함 된 zip 파일이 포함되어 있으므로 모든 것을 복사하여 붙여 넣을 필요가 없습니다.


소스 코드 다운로드 


먼저 약속 한대로 소스 코드에 대한 다운로드 링크가 있습니다.


소스 코드 다운로드 


소스 코드를 다운로드하려면 여기를 클릭하십시오. MIT 라이센스에 따라 릴리스되었으므로 그 위에 빌드하거나 자신의 프로젝트에서 자유롭게 사용하십시오.


폴더 

다음은 zip 파일에서 폴더를 구성하는 방법에 대한 간략한 소개입니다.

  • lib : 모든 PHP 라이브러리 파일을 저장하는 곳.
  • public : 우리는 모든 CSS와 자바 스크립트를 넣습니다.
  • SQL : 데이터베이스를 빌드하는 데 필요한 모든 SQL 파일 모두 가져온 후에 안전하게 삭제할 수 있습니다.

빠른 시작 

  • 폴더에 다운로드하여 압축을 풉니다.
  • 데이터베이스를 작성하고 sql 폴더의 모든 파일을 가져 오십시오.
  • lib / 2a-config.php의 데이터베이스 설정을 원하는 대로 변경하십시오.
  • 하루 종일 예약 데모 인 경우 3a-reserve-day.html, 타임 슬롯 데모 인 경우 3b-reserve-day.html, 기간 데모 인 경우 3c-reserve-range.html을 시작합니다.
  • 누락 된 파일과 AJAX 오류? 파일 경로가 올바른지 확인하십시오.
    3a-reserve-day.html, 3b-reserve-slot.html, 3c-reserve-range.html – 모든 <script> 및 <link> 태그.
    lib/2a-config.php – define('PATH_LIB', 'ABSOLUTE PATH HERE').
    public/3a-reserve-day.js, public/3b-reserve-slot.js, public/3c-reserve-range.js – xhr.open('POST', "PATH/2c-ajax-reserve.php").

개요 및 가정 


실제 스크립트로 들어가기 전에 간단한 시스템 개요에 대한 작은 섹션과 몇 가지 가정을 들었습니다. 따라서 이 안내서에서 무엇을 기대해야 하는지 알고 있습니다.


가정 및 참고 사항


여기에 있는 여러분 중 일부는 기존 프로젝트 나 웹 사이트를 가지고 있고 그 위에 예약 시스템을 구축 할 계획입니다. 그래서 우리는 바퀴를 재발 명하지 않고 기존의 것 위에 다른 관리자 패널을 만들지 않을 것입니다. 이것은 "예약 전용"이며, 새로 시작하는 사용자에게는 아래의 추가 섹션에 관리자 패널을 만드는 방법에 대한 링크가 있습니다.


또한 jQuery, Bootstrap, Angular, Cake, Symfony 등과 같은 타사 프레임 워크는 없습니다.이 가이드는 순수한 HTML, CSS, Javascript 및 PHP로 제공됩니다. 그것은 여러분들이 더 쉽게 통합 할 수 있도록 해야 합니다.


개요 


sys-overview.jpg 


이 프로젝트에는 3 가지 부품이 있습니다 :

  • The database – 지금 예약을 저장할 곳이 필요합니까?
  • Server-side scripts – 사용자 요청을 처리하고, 데이터베이스에 예약을 저장하고, 이메일을 보내는 등
  • Client-side scripts – 예약 페이지 자체

이제 여기의 모든 사람은 하루 종일 예약, 날짜 범위 예약, 시간대 예약, 다음 날만, 30 일 이내에 등 다른 예약 요구 사항을 가지고 있을 수 있습니다. 모든 가능한 경우를 처리하는 것은 불가능 하므로 이 안내서 만 가장 일반적인 시나리오 3 개 –

  • 하루 종일 예약
  • 타임 슬롯 예약
  • 기간 예약

특정 규칙과 제한 사항을 직접 구현해야 합니다.


데이터베이스 


이제 모든 기본 사항을 벗어 났으므로 이제 데이터베이스 기반 예약 테이블을 만들어 프로젝트의 기초를 구축해 보겠습니다.


예약 표 


CREATE TABLE `reservations` ( `res_id` int(11) NOT NULL, `res_name` varchar(255) NOT NULL, `res_email` varchar(255) NOT NULL, `res_tel` varchar(60) NOT NULL, `res_notes` text, `res_date` date DEFAULT NULL, `res_slot` varchar(4) DEFAULT NULL, `res_start` date DEFAULT NULL, `res_end` date DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=latin1; ALTER TABLE `reservations` ADD PRIMARY KEY (`res_id`), ADD KEY `res_name` (`res_name`), ADD KEY `res_email` (`res_email`), ADD KEY `res_tel` (`res_tel`), ADD KEY `res_date` (`res_date`), ADD KEY `res_slot` (`res_slot`), ADD KEY `res_start` (`res_start`), ADD KEY `res_end` (`res_end`); ALTER TABLE `reservations` MODIFY `res_id` int(11) NOT NULL AUTO_INCREMENT; COMMIT; 


필드


FieldDescription
res_idReservation ID. Primary key, auto-increment.
res_nameName of the customer.
res_emailEmail of the customer.
res_telThe telephone number of customer.
res_noteReservation notes, if any.
res_dateFor whole day or time slot booking – You can remove this field if you are doing date range booking.
res_slotFor time slot booking – You can remove this field if you are doing whole day or date range booking.
res_startStart date for date range – You can remove this field if you are doing a single day booking.
res_endEnd date for date range – You can remove this field if you are doing a single day booking.

서버 측 스크립트 


데이터베이스 기반을 완성 했으므로 예약을 처리 할 서버 측 스크립트를 작성해 보겠습니다.


구성 파일 


<?php // MUTE NOTICES error_reporting(E_ALL & ~E_NOTICE); // DATABASE SETTINGS - CHANGE THESE TO YOUR OWN define('DB_HOST', 'localhost'); define('DB_NAME', 'test'); define('DB_CHARSET', 'utf8'); define('DB_USER', 'root'); define('DB_PASSWORD', ''); // FILE PATH define('PATH_LIB', __DIR__ . DIRECTORY_SEPARATOR); ?> 


먼저, 모든 데이터베이스와 설정을 안전하게 유지하기 위해 구성 파일을 만들어 보겠습니다. – 데이터베이스 설정을 자신의 것으로 변경해야 합니다.


예약 라이브러리 


<?php class Res { /* [DATABASE HELPER FUNCTIONS] */ protected $pdo = null; protected $stmt = null; public $error = ""; public $lastID = null; function __construct() { // __construct() : connect to the database // PARAM : DB_HOST, DB_CHARSET, DB_NAME, DB_USER, DB_PASSWORD // ATTEMPT CONNECT try { $str = "mysql:host=" . DB_HOST . ";charset=" . DB_CHARSET; if (defined('DB_NAME')) { $str .= ";dbname=" . DB_NAME; } $this->pdo = new PDO( $str, DB_USER, DB_PASSWORD, [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, PDO::ATTR_EMULATE_PREPARES => false ] ); return true; } // ERROR - DO SOMETHING HERE // THROW ERROR MESSAGE OR SOMETHING catch (Exception $ex) { print_r($ex); die(); } } function __destruct() { // __destruct() : close connection when done if ($this->stmt !== null) { $this->stmt = null; } if ($this->pdo !== null) { $this->pdo = null; } } function exec($sql, $data=null) { // exec() : run insert, replace, update, delete query // PARAM $sql : SQL query // $data : array of data try { $this->stmt = $this->pdo->prepare($sql); $this->stmt->execute($data); $this->lastID = $this->pdo->lastInsertId(); } catch (Exception $ex) { $this->error = $ex; return false; } $this->stmt = null; return true; } function fetch($sql, $cond=null, $key=null, $value=null) { // fetch() : perform select query // PARAM $sql : SQL query // $cond : array of conditions // $key : sort in this $key=>data order, optional // $value : $key must be provided, sort in $key=>$value order $result = false; try { $this->stmt = $this->pdo->prepare($sql); $this->stmt->execute($cond); if (isset($key)) { $result = array(); if (isset($value)) { while ($row = $this->stmt->fetch(PDO::FETCH_NAMED)) { $result[$row[$key]] = $row[$value]; } } else { while ($row = $this->stmt->fetch(PDO::FETCH_NAMED)) { $result[$row[$key]] = $row; } } } else { $result = $this->stmt->fetchAll(); } } catch (Exception $ex) { $this->error = $ex; return false; } $this->stmt = null; return $result; } /* [WHOLE DAY BOOKING] */ function bookDay ($name, $email, $tel, $date, $notes="") { // bookDay() : reserve for the entire day // Check if customer already booked on the day $sql = "SELECT * FROM `reservations` WHERE `res_email`=? AND `res_date`=?"; $cond = [$email, $date]; $check = $this->fetch($sql, $cond); if (count($check)>0) { $this->error = $email . " has already reserved " . $date; return false; } // Process reservation $sql = "INSERT INTO `reservations` (`res_name`, `res_email`, `res_tel`, `res_notes`, `res_date`) VALUES (?,?,?,?,?)"; $cond = [$name, $email, $tel, $notes, $date]; return $this->exec($sql, $cond); } /* [TIME SLOT BOOKING] */ function bookSlot ($name, $email, $tel, $date, $slot, $notes="") { // bookSlot() : reserve for the time slot // Check if customer already booked on the time slot $sql = "SELECT * FROM `reservations` WHERE `res_email`=? AND `res_date`=? AND `res_slot`=?"; $cond = [$email, $date, $slot]; $check = $this->fetch($sql, $cond); if (count($check)>0) { $this->error = $email . " has already reserved " . $date . " " . $slot; return false; } // Process reservation $sql = "INSERT INTO `reservations` (`res_name`, `res_email`, `res_tel`, `res_notes`, `res_date`, `res_slot`) VALUES (?,?,?,?,?,?)"; $cond = [$name, $email, $tel, $notes, $date, $slot]; return $this->exec($sql, $cond); } /* [DATE RANGE BOOKING] */ function bookRange ($name, $email, $tel, $start, $end, $notes="") { // bookRange() : reserve for the date range // Check if customer already booked within the date range $sql = "SELECT * FROM `reservations` WHERE (`res_start` BETWEEN ? AND ?) OR (`res_end` BETWEEN ? AND ?)"; $cond = [$start, $end, $start, $end]; $check = $this->fetch($sql, $cond); if (count($check)>0) { $this->error = $email . " has already reserved between " . $start . " and " . $end; return false; } // Process reservation $sql = "INSERT INTO `reservations` (`res_name`, `res_email`, `res_tel`, `res_notes`, `res_start`, `res_end`) VALUES (?,?,?,?,?,?)"; $cond = [$name, $email, $tel, $notes, $start, $end]; return $this->exec($sql, $cond); } /* [GET RESERVATION] */ // @TODO - There are 101 ways to get/search for the reservations // This is a simple example that will get all reservations within a selected date range // Please do build your own functions in this library! function bookGet ($start, $end) { // bookGet() : get reservation for selected month/year $search = $this->fetch( "SELECT * FROM `reservations` WHERE `res_date` BETWEEN ? AND ?", [$start, $end] ); return count($search)==0 ? false : $search ; } } ?> 


이 라이브러리는 처음에는 방대해 보이지만 두 섹션으로 나뉩니다.

  • 상위 절반은 데이터베이스를 처리하는 도우미 기능입니다.
  • 아래쪽 절반은 예약을 처리하는 기능입니다.
Database Helper Functions
FunctionDescription
__constructThe constructor, automatically connects to the database when the object is being created.
__destructThe destructor, automatically closes the database when the object is being destroyed.
execRun an insert, replace, update, or delete query.
fetchRun a select query
Reservation Functions
FunctionDescription
bookDayUse this if you are doing single full-day booking, remove it if not using.
bookSlotUse this if you are doing single day, time slot booking, remove it if not using.
bookRangeUse this if you are doing date range booking, remove it if not using.
bookGetA sample function on how you can use the database library to retrieve the reservations.

AJAX HANDLER 


<?php // INIT require __DIR__ . DIRECTORY_SEPARATOR . "lib" . DIRECTORY_SEPARATOR . "2a-config.php"; require PATH_LIB . "2b-lib-res.php"; $reslib = new Res(); /* ANTI-SPAM MEASURE YOU CAN CONSIDER * ONLY ALLOW REGISTERED USERS TO BOOK * YOU CAN DO SOMETHING LIKE THIS -> session_start(); if (!is_array($_SESSION['user'])) { die(json_encode([ "status" => 0, "message" => "You must be signed in first" ])); } */ // HANDLE AJAX REQUEST if ($_POST['req']) { switch ($_POST['req']) { // INVALID REQUEST default : echo json_encode([ "status" => 0, "message" => "Invalid request" ]); break; // SHOW CALENDAR OR DATE SELECTOR case "show-cal": // Selected month and year + Various date yoga // * Will take current server time if not provided $thisMonth = (is_numeric($_POST['month']) && $_POST['month']>=1 && $_POST['month']<=12) ? $_POST['month'] : date("n"); $thisYear = is_numeric($_POST['year']) ? $_POST['year'] : date("Y"); $thisStart = strtotime(sprintf("%s-%02u-01", $thisYear, $thisMonth)); $daysInMonth = date("t", $thisStart); $thisEnd = strtotime(sprintf("%s-%02u-%s", $thisYear, $thisMonth, $daysInMonth)); $startDay = date("N", $thisStart); $endDay = date("N", $thisEnd); $yearNow = date("Y"); $monthNow = date("n"); $dayNow = date("j"); // Calculate calendar squares $squares = []; // If the first day of the month is not Sunday, pad with blanks if ($startDay != 7) { for ($i=0; $i<$startDay; $i++) { $squares[] = ["b"=>1]; }} // Days that have already past are not selectable // Earliest selectable is next day - Change this if you want $inow = 1; if ($thisYear==$yearNow && $thisMonth==$monthNow) { for ($inow=1; $inow<=$dayNow; $inow++) { $squares[] = ["d"=>$inow, "b"=>1]; } } // Populate the rest of the selectable days for ($inow; $inow<=$daysInMonth; $inow++) { $squares[] = ["d"=>$inow]; } /* This is an alternate version to show how you can put in date restrictions * For example, close off Sat & Sun reservations $dayNow = date("N", strtotime(sprintf("%s-%02u-%02u", $thisYear, $thisMonth, $inow))); for ($inow; $inow<=$daysInMonth; $inow++) { if ($dayNow==6 || $dayNow==7) { $squares[] = ["d"=>$inow, "b"=>1]; } else { $squares[] = ["d"=>$inow]; } $dayNow++; if ($dayNow==8) { $dayNow = 1; } } */ // If the last day of the month is not Saturday, pad with blanks if ($endDay != 6) { $blanks = $endDay==7 ? 6 : 6-$endDay; for ($i=0; $i<$blanks; $i++) { $squares[] = ["b"=>1]; } } // Draw calendar - Limit your selectable periods here if you want // Month selector $months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]; echo "<select class='month'>"; // Does not allow months that have already passed this year for ($i=($yearNow==$thisYear ? $monthNow : 1); $i<=12; $i++) { printf("<option value='%02u'%s>%s</option>", $i, $i==$thisMonth?" selected":"", $months[$i-1] ); } echo "</select>"; // Year selector echo "<select class='year'>"; // Set to max 3 years from now - change it if you want for ($i=$yearNow; $i<=$yearNow+3; $i++) { printf("<option value='%s'%s>%s</option>", $i, $i==$thisYear?" selected":"", $i ); } echo "</select>"; // Dates echo "<table><tr class='days'>"; // First row - Days of week $days = ["Sun", "Mon", "Tue", "Wed", "Thur", "Fri", "Sat"]; foreach ($days as $d) { echo "<td>$d</td>"; } echo "</tr><tr>"; // Following rows - Days in month $total = count($squares); $first = true; for ($i=0; $i<$total; $i++) { echo "<td class='"; if ($squares[$i]['b']) { echo "blank"; } else if ($first) { echo "active"; $first = false; } else { echo "pick"; } echo "'>"; if ($squares[$i]['d']) { echo $squares[$i]['d']; } echo "</td>"; if ($i!=0 && ($i+1)%7==0) { echo "</tr><tr>"; } } echo "</tr></table>"; break; // SHOW TIME SLOT SELECTOR case "show-slot": /* Do your own time slot logic here - AM/PM, Hourly, Bi-hourly, etc... // You can use the $_POST['date'] variable to restrict // E.g. AM slots for Sat & Sun $selected = date("N", strtotime($_POST['date'])); $weekend = $selected==6 || $selected==7; if ($weekend) { RESTRICT } else { AS USUAL } */ ?> <select> <option value="AM">AM</option>> <option value="PM">PM</option>> </select> <?php break; // ADD NEW RESERVATION - WHOLE DAY BOOKING case "book-day": // Save reservation to database $pass = $reslib->bookDay( $_POST['name'], $_POST['email'], $_POST['tel'], $_POST['date'], $_POST['notes'] ? $_POST['notes'] : "" ); /* You can send an email if you want if ($pass) { $message = ""; foreach ($_POST as $k=>$v) { $message .= $k . " - " . $v; } @mail("admin@yoursite.com", "Reservation receieved", $message); } */ // Server response echo json_encode([ "status" => $pass ? 1 : 0, "message" => $pass ? "OK" : $reslib->error ]); break; // ADD NEW RESERVATION - TIME SLOT BOOKING case "book-slot": // Save reservation to database $pass = $reslib->bookSlot( $_POST['name'], $_POST['email'], $_POST['tel'], $_POST['date'], $_POST['slot'], $_POST['notes'] ? $_POST['notes'] : "" ); /* You can send an email if you want if ($pass) { $message = ""; foreach ($_POST as $k=>$v) { $message .= $k . " - " . $v; } @mail("admin@yoursite.com", "Reservation receieved", $message); } */ // Server response echo json_encode([ "status" => $pass ? 1 : 0, "message" => $pass ? "OK" : $reslib->error ]); break; // ADD NEW RESERVATION - DATE RANGE BOOKING case "book-range": // Save reservation to database $pass = $reslib->bookRange( $_POST['name'], $_POST['email'], $_POST['tel'], $_POST['start'], $_POST['end'], $_POST['notes'] ? $_POST['notes'] : "" ); /* You can send an email if you want if ($pass) { $message = ""; foreach ($_POST as $k=>$v) { $message .= $k . " - " . $v; } @mail("admin@yoursite.com", "Reservation receieved", $message); } */ // Server response echo json_encode([ "status" => $pass ? 1 : 0, "message" => $pass ? "OK" : $reslib->error ]); break; }} 


마지막으로, 라이브러리 파일은 자체적으로 아무것도 하지 않으므로 이 미친 것처럼 보이는 AJAX 핸들러 스크립트의 이유는… 혼란스러워 보이지만 실제로는 아무 것도 아닙니다.


아약스 란?! 


AJAX 핸들러의 작동 방식은 매우 간단합니다. 처리하려는 대상에 대해 이 스크립트에 $_POST['req'] 요청을 보내고 필요한 매개 변수가 옵니다.


RequestDescription
show-calGenerates an HTML date picker for the given period $_POST['month'] and $_POST['year']. Used by all 3 different booking scenarios, will go into further details below.
show-slotShows the available time slots for the given date $_POST['date'], this is just a simple AM/PM selector. Modify this to fit your own project – Could be different hourly slots, or maybe even bi-hourly.
book-dayUsed for full-day booking, you can remove this if you are offering timeslot or date range booking. Requires name, email, telephone, date, and an optional note.
book-slotUsed for timeslot booking, you can remove this if you are offering full-day or date range booking. Requires name, email, telephone, date, timeslot, and an optional note.
book-rangeUsed for date range booking, you can remove this if you are offering full-day or timeslot booking. Requires name, email, telephone, start date, end date, and an optional note.

따라서 이 스크립트에서 사용하지 않는 일부 섹션을 실제로 제거 할 수 있으며 실제로 그렇게 복잡하지는 않습니다.


THE CRAZY CALENDAR 


서버 측 스크립트의 가장 열악한 부분은 아마도 주어진 달에 대해 선택 가능한 날짜를 생성하는 것입니다. 여기서는 AJAX 핸들러의 이 섹션을 자세히 살펴볼 것입니다.

  • 스크립트의 상단 부분은 많은 일, 월 및 연도 계산을 수행합니다 – 선택한 기간의 첫날, 마지막 날, 월의 일 등…
  • a $ _POST [ 'month'] 및 $ _POST [ 'year']를 통과하지 않으면 스크립트는 기본적으로 서버에서 현재 시간을 사용합니다.
  • HTML 달력을 생성하기 전에 모든 렌더링 정보를 포함하기 위해 $ squares 배열을 사용합니다.
  • 처음에는 일요일에 시작하지 않는 달이 많습니다. 예를 들어, 달의 첫 번째 날은 화요일 일 수 있으며 일요일부터 월요일까지 빈 사각형으로 달력을 채워야 합니다. 이렇게 하려면 단순히 $ squares [] = [ "b"=> 1] twice 빈 사각형을 채 웁니다.
  • 다음은 월 자체의 요일입니다. – $ squares [] = [ "d"=> DAY]로 채웁니다.
  • 특정 날짜를 사용할 수 없도록 차단하려면 $ squares [] = [ "d"=> DAY, "b"=> 1]을 사용할 수 있습니다.
  • 그런 다음 몇 달이 토요일에 끝나지 않으므로 동일한 빈 패딩 트릭을 수행합니다.
  • 마지막으로, $$ squares에 포함 된 정보에서 HTML 달력을 렌더링 합니다.


클라이언트 측 스크립트 


마지막으로 실제 HTML 예약 페이지 자체를 구축하여 퍼즐 만 완성하면 됩니다. 여기서 3 가지 시나리오를 각각 실행하겠습니다 ... 적용되지 않는 시나리오는 건너 뛰십시오.


하루 종일 예약 


HTML 


<!DOCTYPE html> <html> <head> <title> PHP Reservation Demo - Single Full Day Booking </title> <script src="public/3a-reserve-day.js"></script> <link href="public/3-theme.css" rel="stylesheet"> </head> <body> <h1> RESERVATION </h1> <form id="res_form" onsubmit="return res.save()"> <label for="res_name">Name</label> <input type="text" required id="res_name"/> <label for="res_email">Email</label> <input type="email" required id="res_email"/> <label for="res_tel">Telephone Number</label> <input type="text" required id="res_tel"/> <label for="res_notes">Notes (if any)</label> <input type="text" id="res_notes"/> <label>Reservation Date</label> <div id="res_date" class="calendar"></div> <button id="res_go" disabled> Submit </button> </form> </body> </html> 


이것은 이해하기 쉬워야 합니다 – 단지 일반적인 HTML 예약 양식입니다. 그러나 여기 두 가지를 주의하십시오.

  • 날짜 선택기를 AJAX를 통해 <div id = "res_date">에 로드합니다. 이런 식으로, 서버 측에서 모든 적절한 제한 및 점검을 먼저 수행 할 수 있습니다.
  • 제출 버튼이 비활성화되었습니다. 날짜 선택기가 완전히 로드 된 경우에만 이 기능을 사용하도록 설정합니다.

자바 스크립트 


var res = { cal : function () { // res.cal() : show calendar // Disable submit first document.getElementById("res_go").disabled = true; // AJAX data var data = new FormData(); data.append('req', 'show-cal'); // Get selected month & year - If they exist var select = document.querySelector("#res_date select.month"); if (select!=null) { data.append('month', select.value); select = document.querySelector("#res_date select.year"); data.append('year', select.value); } // AJAX call var xhr = new XMLHttpRequest(); xhr.open('POST', "2c-ajax-reserve.php", true); xhr.onload = function(){ // Set contents, click, change actions document.getElementById("res_date").innerHTML = this.response; select = document.querySelector("#res_date select.month"); select.addEventListener("change", res.cal); select = document.querySelector("#res_date select.year"); select.addEventListener("change", res.cal); select = document.querySelectorAll("#res_date .pick, #res_date .active"); for (var i of select) { i.addEventListener("click", res.pick); } // Enable submit document.getElementById("res_go").disabled = false; }; xhr.send(data); }, pick : function () { // res.pick() : change selected date var select = document.querySelector("#res_date .active"); if (select!=this) { select.classList.remove("active"); select.classList.add("pick"); this.classList.remove("pick"); this.classList.add("active"); } }, save : function () { // res.save() : save the reservation // Selected date var select = document.querySelector("#res_date td.active").innerHTML; if (select.length==1) { select = "0" + select; } select = document.querySelector("#res_date select.month").value + "-" + select; select = document.querySelector("#res_date select.year").value + "-" + select; // AJAX data var data = new FormData(); data.append('req', 'book-day'); data.append('name', document.getElementById("res_name").value); data.append('email', document.getElementById("res_email").value); data.append('tel', document.getElementById("res_tel").value); data.append('notes', document.getElementById("res_notes").value); data.append('date', select); // AJAX call var xhr = new XMLHttpRequest(); xhr.open('POST', "2c-ajax-reserve.php", true); xhr.onload = function(){ var res = JSON.parse(this.response); // OK - Redirect to thank you page if (res.status==1) { location.href = "3d-thank-you.html"; } // ERROR - show error else { alert(res.message); } }; xhr.send(data); return false; } }; window.addEventListener("load", res.cal); 


이 자바 스크립트는 복잡해 보이지만 실제로는 3 개의 함수 만 있습니다.


FunctionDescription
res.cal()This function will fire up when the page is initially loaded, and whenever the user changes the month/year. It will do an AJAX call to the server to render the calendar for the selected period.
res.pick()This function is fired when the user clicks on a date on the calendar. It simply updates the HTML to the newly selected date.
res.save()Submit and process the reservation form.

타임 슬롯 예약 


HTML 


<!DOCTYPE html> <html> <head> <title> PHP Reservation Demo - Single Time Slot Booking </title> <script src="public/3b-reserve-slot.js"></script> <link href="public/3-theme.css" rel="stylesheet"> </head> <body> <h1> RESERVATION </h1> <form id="res_form" onsubmit="return res.save()"> <label for="res_name">Name</label> <input type="text" required id="res_name"/> <label for="res_email">Email</label> <input type="email" required id="res_email"/> <label for="res_tel">Telephone Number</label> <input type="text" required id="res_tel"/> <label for="res_notes">Notes (if any)</label> <input type="text" id="res_notes"/> <label>Reservation Date</label> <div id="res_date" class="calendar"></div> <label>Reservation Slot</label> <div id="res_slot"></div> <button id="res_go" disabled> Submit </button> </form> </body> </html> 


타임 슬롯 예약의 HTML은 하루 종일과 거의 동일합니다. – 이것은 단순한 HTML 양식이지만 참고하십시오.


  • 날짜 선택기는 AJAX를 통해 <div id = "res_date">에 로드됩니다.
  • 다음으로 타임 슬롯 선택기가 AJAX를 통해 <div id = "res_slot">에 로드됩니다.
  • 제출 버튼이 비활성화되었습니다. 날짜 선택기와 타임 슬롯 선택기가 모두 로드 된 경우에만 이 기능을 사용할 수 있습니다.

자바 스크립트 


var res = { cal : function () { // res.cal() : show calendar // Disable submit first document.getElementById("res_go").disabled = true; // AJAX data var data = new FormData(); data.append('req', 'show-cal'); // Get selected month & year - If they exist var select = document.querySelector("#res_date select.month"); if (select!=null) { data.append('month', select.value); select = document.querySelector("#res_date select.year"); data.append('year', select.value); } // AJAX call var xhr = new XMLHttpRequest(); xhr.open('POST', "2c-ajax-reserve.php", true); xhr.onload = function(){ // Set contents, click, change actions document.getElementById("res_date").innerHTML = this.response; select = document.querySelector("#res_date select.month"); select.addEventListener("change", res.cal); select = document.querySelector("#res_date select.year"); select.addEventListener("change", res.cal); select = document.querySelectorAll("#res_date .pick, #res_date .active"); for (var i of select) { i.addEventListener("click", res.pick); } // Load time slots res.slot(); }; xhr.send(data); }, slot : function () { // res.slot() : load time slot selector // Disable submit first document.getElementById("res_go").disabled = true; // Selected date var select = document.querySelector("#res_date td.active").innerHTML; if (select.length==1) { select = "0" + select; } select = document.querySelector("#res_date select.month").value + "-" + select; select = document.querySelector("#res_date select.year").value + "-" + select; // AJAX data var data = new FormData(); data.append('req', 'show-slot'); data.append('date', select); // AJAX call var xhr = new XMLHttpRequest(); xhr.open('POST', "2c-ajax-reserve.php", true); xhr.onload = function(){ // Set contents document.getElementById("res_slot").innerHTML = this.response; // Enable submit document.getElementById("res_go").disabled = false; }; xhr.send(data); }, pick : function () { // res.pick() : change selected date var select = document.querySelector("#res_date .active"); if (select!=this) { select.classList.remove("active"); select.classList.add("pick"); this.classList.remove("pick"); this.classList.add("active"); res.slot(); } }, save : function () { // res.save() : save the reservation // Selected date var select = document.querySelector("#res_date td.active").innerHTML; if (select.length==1) { select = "0" + select; } select = document.querySelector("#res_date select.month").value + "-" + select; select = document.querySelector("#res_date select.year").value + "-" + select; // AJAX data var data = new FormData(); data.append('req', 'book-slot'); data.append('name', document.getElementById("res_name").value); data.append('email', document.getElementById("res_email").value); data.append('tel', document.getElementById("res_tel").value); data.append('notes', document.getElementById("res_notes").value); data.append('date', select); data.append('slot', document.querySelector("#res_slot select").value); // AJAX call var xhr = new XMLHttpRequest(); xhr.open('POST', "2c-ajax-reserve.php", true); xhr.onload = function(){ var res = JSON.parse(this.response); // OK - Redirect to thank you page if (res.status==1) { location.href = "3d-thank-you.html"; } // ERROR - show error else { alert(res.message); } }; xhr.send(data); return false; } }; window.addEventListener("load", res.cal); 


복잡한 자바 스크립트? 아니. 여기에는 4 개의 AJAX 기능 만 있습니다.


FunctionDescription
res.cal()Fires up when the page is initially loaded, and whenever the user changes the month/year. It will do an AJAX call to the server to render the calendar for the selected period.
res.slot()Follows up after res.cal, or whenever the user chooses a different date. This will load the timeslot selector via an AJAX call.
res.pick()Fires up when the user picks a different date. Updates the HTML interface, and calls the res.slot function to refresh the available timeslots for the selected date.
res.save()Proceed to process the reservation.

날짜 범위 예약 


HTML 


<!DOCTYPE html> <html> <head> <title> PHP Reservation Demo - Date Range Booking </title> <script src="public/3c-reserve-range.js"></script> <link href="public/3-theme.css" rel="stylesheet"> </head> <body> <h1> RESERVATION </h1> <form id="res_form" onsubmit="return res.save()"> <label for="res_name">Name</label> <input type="text" required id="res_name" value="John Doe"/> <label for="res_email">Email</label> <input type="email" required id="res_email" value="john@doe.com"/> <label for="res_tel">Telephone Number</label> <input type="text" required id="res_tel" value="123456"/> <label for="res_notes">Notes (if any)</label> <input type="text" id="res_notes" value="test"/> <label>Reservation Start</label> <div id="res_start" class="calendar"></div> <label>Reservation End</label> <div id="res_end" class="calendar"></div> <button id="res_go" disabled> Submit </button> </form> </body> </html> 


여기에 간단한 HTML 양식이 있지만 약간의 왜곡이 있습니다.


  • 시작 및 종료 날짜 선택기는 AJAX를 통해 로드됩니다.
  • 제출 버튼은 기본적으로 비활성화 되어 있습니다. 두 날짜 선택기가 모두 로드 된 경우에만 활성화합니다.

자바 스크립트 


var res = { calstart : function () { // res.calstart() : show calendar for date start res.cal("start"); }, calend : function () { // res.calend() : show calendar for date end res.cal("end"); }, cal : function (target) { // res.cal() : show calendar // target : start or end // Disable submit first document.getElementById("res_go").disabled = true; // Target event handlers var calchange = target=="start" ? res.calstart : res.calend ; var picker = target=="start" ? res.pickstart : res.pickend ; // AJAX data var data = new FormData(); data.append('req', 'show-cal'); // Get selected month & year - If they exist var select = document.querySelector("#res_" + target +" select.month"); if (select!=null) { data.append('month', select.value); select = document.querySelector("#res_" + target + " select.year"); data.append('year', select.value); } // AJAX call var xhr = new XMLHttpRequest(); xhr.open('POST', "2c-ajax-reserve.php", true); xhr.onload = function(){ // Set contents, click, change actions document.getElementById("res_" + target).innerHTML = this.response; select = document.querySelector("#res_" + target + " select.month"); select.addEventListener("change", calchange); select = document.querySelector("#res_" + target + " select.year"); select.addEventListener("change", calchange); select = document.querySelectorAll("#res_" + target + " .pick, #res_" + target + " .active"); for (var i of select) { i.addEventListener("click", picker); } // Enable submit document.getElementById("res_go").disabled = false; }; xhr.send(data); }, pickstart : function () { // res.pickstart() : change selected date for date start res.pick('start', this); }, pickend : function () { // res.pickend() : change selected date for date end res.pick('end', this); }, pick : function (target, picked) { // res.pick() : change selected date // target : start or end // picked : current element being clicked on var select = document.querySelector("#res_" + target + " .active"); if (select!=picked) { select.classList.remove("active"); select.classList.add("pick"); picked.classList.remove("pick"); picked.classList.add("active"); } }, save : function () { // res.save() : save the reservation // Selected start date var start = document.querySelector("#res_start td.active").innerHTML; if (start.length==1) { start = "0" + start; } start = document.querySelector("#res_start select.month").value + "-" + start; start = document.querySelector("#res_start select.year").value + "-" + start; // Selected end date var end = document.querySelector("#res_end td.active").innerHTML; if (end.length==1) { end = "0" + end; } end = document.querySelector("#res_end select.month").value + "-" + end; end = document.querySelector("#res_end select.year").value + "-" + end; // End date must be after start date if (Date.parse(start)>=Date.parse(end)) { alert("End date cannot be earlier than start date!"); } else { // AJAX data var data = new FormData(); data.append('req', 'book-range'); data.append('name', document.getElementById("res_name").value); data.append('email', document.getElementById("res_email").value); data.append('tel', document.getElementById("res_tel").value); data.append('notes', document.getElementById("res_notes").value); data.append('start', start); data.append('end', end); // AJAX call var xhr = new XMLHttpRequest(); xhr.open('POST', "2c-ajax-reserve.php", true); xhr.onload = function(){ var res = JSON.parse(this.response); // OK - Redirect to thank you page if (res.status==1) { location.href = "3d-thank-you.html"; } // ERROR - show error else { alert(res.message); } }; xhr.send(data); } return false; } }; window.addEventListener("load", function(){ res.calstart(); res.calend(); }); 


FunctionDescription
res.cal()Loads the calendar via AJAX. Either for the start or end date.
res.calstart()Fires up on page load, or when the user changes the month/date of the start date. Calls res.cal to load the calendar.
res.calend()Fires up on page load, or when the user changes the month/date of the end date. Calls res.cal to load the calendar.
res.pick()Updates the HTML calendar to show a newly selected date.
res.pickstart()Fires when the user clicks on a date on the start date. Calls res.pick to update the interface.
res.pickend()Fires when the user clicks on a date on the end date. Calls res.pick to update the interface.
res.save()Proceed to save the reservation on the server.

CSS 


/* [CALENDAR] */ /* Month & year selector */ div.calendar select { width: 50% !important; padding: 5px } div.calendar table { width: 100%; border-collapse: seperate; margin-top: 10px; } /* All the cells in general */ div.calendar table td { width: 14%; padding: 5px; text-align: center; } /* First row - days of week */ div.calendar table tr.days td { background: #888; color: #fff; font-weight: bold; } /* Currently chosen date */ div.calendar table td.active { background: #d64646; color: #fff; } /* Dates you can choose */ div.calendar table td.pick:hover { cursor: pointer; background: #ffe5d3; } /* Blank cells */ div.calendar td.blank { background: #ddd; } /* [DOES NOT MATTER] */ html, body { font-family: arial, sans-serif; } #res_form { padding: 15px; max-width: 400px; background: #f2f2f2; } #res_form label, #res_form input, #res_form button, #res_form select { font-size: 16px; width: 100%; box-sizing: border-box; } #res_form label, #res_form input, #res_form button { display: block; } #res_form label { color: #555; margin: 5px 0; } #res_form input, #res_form select { padding: 5px; } #res_form button { margin-top: 10px; background: #b53732; color: #fff; padding: 10px; border: 0; } 


이 예제에서 일부 화장품은 프로젝트에서 사용할 수 있는 유일한 부분은 아마도 달력의 스타일 일 것입니다.


감사합니다 페이지 


<!DOCTYPE html> <html> <head> <title> PHP Reservation Demo - Thank You Page </title> <link href="public/3-theme.css" rel="stylesheet"> </head> <body> <h1> THANK YOU! </h1> <p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur mollis erat nec tortor efficitur, non pulvinar ligula scelerisque. </p> <p> Vestibulum facilisis quis quam id lobortis. Nullam bibendum aliquet ultrices. Aliquam elementum neque quis massa tristique cursus. </p> </body> </html> 


감사 페이지… 자신을 위해 적절한 페이지를 만드십시오.


유용한 비트 


이것으로 코드가 완성되었으며 여기에 유용한 몇 가지 추가 기능이 있습니다.


할 일 목록 


이것이 이 단순한 시스템에 대한 것이지만 여전히 골격입니다. 고객 또는 비즈니스에 101 가지 더 다양한 요구 사항이 있을 수 있으므로 다음은 이 안내서를 기반으로 작성하려는 작은 목록입니다.

  • 예약 라이브러리 및 AJAX 처리기 강화 – 예약 날짜 및 슬롯에 대한 자체 제한 및 규칙을 설정하십시오.
  • 루프 닫기 – 사용자가 예약을 제출 한 후 발생하는 상황. 이메일을 보내다? 전화해서 확인 하시겠습니까? 자신의 가용성을 먼저 확인 하시겠습니까? 보증금을 요청 하시겠습니까?
  • 상당히 많은 화장품 – 자신의 프로젝트에 적합합니다.
  • 기존 웹 사이트에 올바르게 통합하거나 새로운 관리자 패널을 구축하십시오.
  • 완벽한 관리 및 보고서 – 지정된 기간 동안 예약을 추출하고 스프레드 시트로 내보내기 등

추가 분야 또는 수정? 


필드를 추가하거나 이 시스템을 수정하고 싶습니까? 이 안내서의 3 가지 부분 만 기억하고 하나씩 해결하면 괜찮습니다.


  • 데이터베이스 – 먼저 데이터베이스 테이블을 업데이트하고 원하는 필드를 작성하거나 제거하십시오.
  • 서버 측 스크립트 – 예약 라이브러리 파일을 업데이트하고 필요한 경우 고유 한 기능을 작성하십시오. 또한 새 필드를 포함하도록 AJAX 핸들러 스크립트를 업데이트하십시오.
  • 클라이언트 측 스크립트 – 마지막으로 HTML 및 Javascript를 업데이트하십시오.

관리자 패널 및 로그인 


새로운 프로젝트를 시작하는 여러분에게. 예약 시스템이 있을 수 있지만 여전히 적절한 사용자 데이터베이스, 로그인 메커니즘 및 관리자 패널이 필요합니다.



댓글목록 0

등록된 댓글이 없습니다.

웹학교 로고

온라인 코딩학교

코리아뉴스 2001 - , All right reserved.