翻譯|使用教程|編輯:龔雪|2023-11-30 11:32:15.800|閱讀 87 次
概述:本文將為大家介紹如何用日程控件DHTMLX Scheduler和Angular制作酒店預訂日歷,歡迎下載最新版組件體驗~
# 界面/圖表報表/文檔/IDE等千款熱門軟控件火熱銷售中 >>
dhtmlxScheduler是一個類似于Google日歷的JavaScript日程安排控件,日歷事件通過Ajax動態加載,支持通過拖放功能調整事件日期和時間,事件可以按天,周,月三個種視圖顯示。
在本教程中,我們將使用兩個強大的工具:DHTMLX Scheduler庫和Angular框架來創建一個全面的酒店客房預訂應用程序。在上文中(點擊這里回顧>>)我們為大家介紹了提供保存數據中的數據加載、CRUD操作實現等,本文將繼續介紹服務器配置。
現在讓我們繼續為應用程序設置Node.js服務器,本教程使用Express框架和MySQL作為數據存儲。
您應該設置MySQL服務器,或者可以使用其他服務,例如免費MySQL托管。
添加express、mysql和date-format-lite模塊:
$ npm install express mysql date-format-lite
server.js被指定為上面的輸入點,現在讓我們在項目的根目錄下創建server文件夾,并添加server.js文件,代碼如下:
const express = require('express'); // use Express const app = express(); // create application const port = 3000; // port for listening const cors = require('cors'); app.use(cors()); // enable CORS for all routes // MySQL will be used for db access and util to promisify queries const util = require('util'); const mysql = require('mysql'); // use your own parameters for database const mysqlConfig = { 'connectionLimit': 10, 'host': 'localhost', 'user': 'root', 'password': '', 'database': 'room_reservation_node' }; app.use(express.json()); // Enable JSON body parsing // return static pages from the './public' directory app.use(express.static(__dirname + '/public')); // start server app.listen(port, () = { console.log('Server is running on port ' + port + '...'); }); const router = require('./router'); // open connection to mysql const connectionPool = mysql.createPool(mysqlConfig); connectionPool.query = util.promisify(connectionPool.query); // add listeners to basic CRUD requests const DatabaseHandler = require('./databaseHandler'); const databaseHandler = new DatabaseHandler(connectionPool); router.setRoutes(app, '/data', databaseHandler);
然后打開package.json文件夾,將start語句替換為:
"scripts": { "ng": "ng", "start": "concurrently \"node server/server.js\" \"ng serve\"", …
我們將使用concurrent包來同時啟動服務器和客戶端應用程序,因此添加concurrent模塊:
$ npm install concurrently
讓我們將Scheduler連接到數據庫,并定義在其中讀取和寫入項的方法。
首先我們需要一個數據庫來工作,您可以使用自己喜歡的mysql-client或通過控制臺創建數據庫。
要使用mysql-client創建數據庫,打開它并執行下面的代碼,創建預訂表:
CREATE TABLE `reservations` ( `id` bigint(20) unsigned AUTO_INCREMENT, `start_date` datetime NOT NULL, `end_date` datetime NOT NULL, `text` varchar(255) DEFAULT NULL, `room` varchar(255) DEFAULT NULL, `booking_status` varchar(255) DEFAULT NULL, `is_paid` BOOLEAN DEFAULT NULL CHECK (is_paid IN (0, 1)), PRIMARY KEY (`id`) ) DEFAULT CHARSET=utf8;
讓我們添加一些測試數據:
INSERT INTO `reservations` VALUES (2, '2023-08-01', '2023-08-11', 'RSV2023-08-01ABC124', 3, 4, true); INSERT INTO `reservations` VALUES (3, '2023-08-07', '2023-08-17', 'RSV2023-08-07ABC126', 5, 3, true); INSERT INTO `reservations` VALUES (4, '2023-08-04', '2023-08-16', 'RSV2023-08-04ABC125', 7, 4, false); INSERT INTO `reservations` VALUES (13, '2023-07-28', '2023-08-14', 'RSV2023-07-28ABC123', 1, 4, true); INSERT INTO `reservations` VALUES (14, '2023-08-14', '2023-08-27', 'RSV2023-08-14ABC129', 1, 3, false); INSERT INTO `reservations` VALUES (15, '2023-08-19', '2023-08-29', 'new booking', 4, 1, false); INSERT INTO `reservations` VALUES (16, '2023-08-24', '2023-08-31', 'new booking', 11, 1, false); INSERT INTO `reservations` VALUES (17, '2023-08-17', '2023-08-26', 'RSV2023-08-17ABC135', 6, 2, false); INSERT INTO `reservations` VALUES (18, '2023-08-18', '2023-08-31', 'RSV2023-08-18ABC139', 9, 2, false); INSERT INTO `reservations` VALUES (19, '2023-08-02', '2023-08-12', 'RSV2023-08-02ABC127', 10, 4, true); INSERT INTO `reservations` VALUES (20, '2023-08-12', '2023-08-21', 'RSV2023-08-12ABC130', 10, 3, false);
創建房間表:
CREATE TABLE `rooms` ( `id` bigint(20) unsigned AUTO_INCREMENT, `value` varchar(255) DEFAULT NULL, `label` varchar(255) DEFAULT NULL, `type` varchar(255) DEFAULT NULL, `cleaning_status` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`) ) DEFAULT CHARSET=utf8;
添加一些測試數據:
INSERT INTO `rooms` VALUES ('1', '1', '101', '1', '1'); INSERT INTO `rooms` VALUES ('2', '2', '102', '1', '3'); INSERT INTO `rooms` VALUES ('3', '3', '103', '1', '2'); INSERT INTO `rooms` VALUES ('4', '4', '104', '1', '1'); INSERT INTO `rooms` VALUES ('5', '5', '105', '2', '1'); INSERT INTO `rooms` VALUES ('6', '6', '201', '2', '2'); INSERT INTO `rooms` VALUES ('7', '7', '202', '2', '1'); INSERT INTO `rooms` VALUES ('8', '8', '203', '3', '3'); INSERT INTO `rooms` VALUES ('9', '9', '204', '3', '3'); INSERT INTO `rooms` VALUES ('10', '10', '301', '4', '2'); INSERT INTO `rooms` VALUES ('11', '11', '302', '4', '2'); INSERT INTO `rooms` VALUES ('12', '12', '303', '1', '2');
創建roomTypes表:
CREATE TABLE `roomTypes` ( `id` bigint(20) unsigned AUTO_INCREMENT, `value` varchar(255) DEFAULT NULL, `label` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`) ) DEFAULT CHARSET=utf8;
添加一些測試數據:
INSERT INTO `roomTypes` VALUES ('1', '1', '1 bed'); INSERT INTO `roomTypes` VALUES ('2', '2', '2 bed'); INSERT INTO `roomTypes` VALUES ('3', '3', '3 bed'); INSERT INTO `roomTypes` VALUES ('4', '4', '4 bed');
創建cleaningStatuses表:
CREATE TABLE `cleaningStatuses` ( `id` bigint(20) unsigned AUTO_INCREMENT, `value` varchar(255) DEFAULT NULL, `label` varchar(255) DEFAULT NULL, `color` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`) ) DEFAULT CHARSET=utf8;
添加一些測試數據:
INSERT INTO `cleaningStatuses` VALUES ('1', '1', 'Ready', '#43a047'); INSERT INTO `cleaningStatuses` VALUES ('2', '2', 'Dirty', '#e53935'); INSERT INTO `cleaningStatuses` VALUES ('3', '3', 'Clean up', '#ffb300');
創建bookingStatuses表:
CREATE TABLE `bookingStatuses` ( `id` bigint(20) unsigned AUTO_INCREMENT, `value` varchar(255) DEFAULT NULL, `label` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`) ) DEFAULT CHARSET=utf8;
添加一些測試數據:
INSERT INTO `bookingStatuses` VALUES ('1', '1', 'New'); INSERT INTO `bookingStatuses` VALUES ('2', '2', 'Confirmed'); INSERT INTO `bookingStatuses` VALUES ('3', '3', 'Arrived'); INSERT INTO `bookingStatuses` VALUES ('4', '4', 'Checked Out');
所有的讀/寫邏輯都將在一個名為DatabaseHandler的單獨模塊中定義,它將使用mysql連接并在指定的表中執行簡單的CRUD操作:讀取所有項,插入新項,更新或刪除現有項。為此創建databaseHandler.js文件,并將以下代碼添加到其中:
require('date-format-lite'); // add date format class DatabaseHandler { constructor(connection, table) { this._db = connection; this.table = 'reservations'; } /// ↓↓↓ reservations handler ↓↓↓ // get reservations, use dynamic loading if parameters sent async getAllReservations(params) { let query = 'SELECT * FROM ??'; let queryParams = [ this.table ]; let result = await this._db.query(query, queryParams); result.forEach((entry) = { // format date and time entry.start_date = entry.start_date.format('YYYY-MM-DD hh:mm'); entry.end_date = entry.end_date.format('YYYY-MM-DD hh:mm'); }); return result; } // create new reservation async insert(data) { let result = await this._db.query( 'INSERT INTO ?? (`start_date`, `end_date`, `text`, `room`, `booking_status`, `is_paid`) VALUES (?,?,?,?,?,?)', [this.table, data.start_date, data.end_date, data.text, data.room, data.booking_status, data.is_paid]); return { action: 'inserted', tid: result.insertId } } // update reservation async update(id, data) { await this._db.query( 'UPDATE ?? SET `start_date` = ?, `end_date` = ?, `text` = ?, `room` = ?, `booking_status` = ?, `is_paid` = ? WHERE id = ?', [this.table, data.start_date, data.end_date, data.text, data.room, data.booking_status, data.is_paid, id]); return { action: 'updated' } } // delete reservation async delete(id) { await this._db.query( 'DELETE FROM ?? WHERE `id`=? ;', [this.table, id]); return { action: 'deleted' } } /// ↑↑↑ reservations handler ↑↑↑ /// ↓↓↓ room cleanup status handler ↓↓↓ // get rooms async getAllRooms(params) { let query = 'SELECT * FROM ??'; let queryParams = [ 'rooms' ]; let result = await this._db.query(query, queryParams); return result; } // update room cleanup status async updateRoomCleaningStatus(id, data) { await this._db.query( 'UPDATE ?? SET `value` = ?, `label` = ?, `type` = ?, `cleaning_status` = ? WHERE id = ?', ['rooms', data.key, data.label, data.type, data.cleaning_status, id]); return { action: 'updated' } } /// ↑↑↑ room cleanup status handler ↑↑↑ /// ↓↓↓ get room types ↓↓↓ async getRoomTypes(params) { let query = 'SELECT * FROM ??'; let queryParams = [ 'roomTypes' ]; let result = await this._db.query(query, queryParams); return result; } /// ↑↑↑ get room types ↑↑↑ /// ↓↓↓ get cleaning statuses ↓↓↓ async getCleaningStatuses(params) { let query = 'SELECT * FROM ??'; let queryParams = [ 'cleaningStatuses' ]; let result = await this._db.query(query, queryParams); return result; } /// ↑↑↑ get cleaning statuses ↑↑↑ /// ↓↓↓ get booking statuses ↓↓↓ async getBookingStatuses(params) { let query = 'SELECT * FROM ??'; let queryParams = [ 'bookingStatuses' ]; let result = await this._db.query(query, queryParams); return result; } /// ↑↑↑ get booking statuses ↑↑↑ } module.exports = DatabaseHandler;
然后需要設置路由,以便放置在頁面上的調度器可以訪問存儲。為此創建另一個helper模塊,并將其命名為router.js:
function callMethod (method) { return async (req, res) = { let result; try { result = await method(req, res); } catch (e) { result = { action: 'error', message: e.message } } res.send(result); } }; module.exports = { setRoutes (app, prefix, databaseHandler) { /// ↓↓↓ reservations router ↓↓↓ app.get(`${prefix}/reservations`, callMethod((req) = { return databaseHandler.getAllReservations(req.query); })); app.post(`${prefix}/reservations`, callMethod((req) = { return databaseHandler.insert(req.body); })); app.put(`${prefix}/reservations/:id`, callMethod((req) = { return databaseHandler.update(req.params.id, req.body); })); app.delete(`${prefix}/reservations/:id`, callMethod((req) = { return databaseHandler.delete(req.params.id); })); /// ↑↑↑ reservations router ↑↑↑ /// ↓↓↓ rooms router ↓↓↓ app.get(`${prefix}/collections/rooms`, callMethod((req) = { return databaseHandler.getAllRooms(req.query); })); app.put(`${prefix}/collections/rooms/:id`, callMethod((req) = { return databaseHandler.updateRoomCleaningStatus(req.params.id, req.body); })); /// ↑↑↑ rooms router ↑↑↑ /// ↓↓↓ room types router ↓↓↓ app.get(`${prefix}/collections/roomTypes`, callMethod((req) = { return databaseHandler.getRoomTypes(req.query); })); /// ↑↑↑ room types router ↑↑↑ /// ↓↓↓ cleaning statuses router ↓↓↓ app.get(`${prefix}/collections/cleaningStatuses`, callMethod((req) = { return databaseHandler.getCleaningStatuses(req.query); })); /// ↑↑↑ cleaning statuses router ↑↑↑ /// ↓↓↓ booking statuses router ↓↓↓ app.get(`${prefix}/collections/bookingStatuses`, callMethod((req) = { return databaseHandler.getBookingStatuses(req.query); })); /// ↑↑↑ booking statuses router ↑↑↑ } };
它所做的就是設置應用程序來偵聽調度器可以發送的請求url,并調用存儲的適當方法。請注意,所有方法都包裝在try-catch塊中,以便能夠捕獲任何錯誤并向客戶機返回適當的錯誤響應。
還要注意,異常消息是直接寫入API響應的。這在開發過程中非常方便,但在生產環境中,對客戶端隱藏這些消息可能是一個好主意,因為到達那里的原始mysql異??赡馨舾袛祿?
現在如果您打開應用程序頁面,可以看到一個帶有預訂的調度程序。可以在調度程序中創建、刪除和修改項,即使重新加載頁面,您所做的任何更改也將保留。
本站文章除注明轉載外,均為本站原創或翻譯。歡迎任何形式的轉載,但請務必注明出處、不得修改原文相關鏈接,如果存在內容上的異議請郵件反饋至chenjj@fc6vip.cn
文章轉載自:慧都網