สวัสดีครับเพื่อนๆ ชาว trakun.com ทุกคน กลับมาพบกับผม ตระกูล อ่อนรัตน์ อีกครั้งใน EP19 ครับ!
ลองนึกถึงความวุ่นวายในออฟฟิศ หรือหน่วยงานของคุณดูครับ เมื่อถึงเวลาที่ทุกคนจำเป็นต้องใช้ “ห้องประชุมใหญ่” พร้อมกัน หรือจำเป็นต้องออกไปปฏิบัติงานนอกสถานที่แล้วต้องใช้ “รถยนต์ส่วนกลาง” ในวันเดียวกัน… ปัญหาที่มักจะตามมาคืออะไรครับ?
“อ้าว! พี่จองคันนี้ไว้ในสมุดแล้วนะทำไมเราเอาไปขับ?” หรือ “ห้องประชุมนี้ใครจองไว้? ทำไมเปิดเข้าไปเจออีกทีมกำลังพรีเซนต์งานอยู่?”
นี่คือปัญหาคลาสสิกที่เกิดขึ้นในทุกที่ที่ยังใช้ระบบ “จองผ่านสมุด” หรือ “พิมพ์บอกในไลน์กลุ่ม” ครับ เพราะมันไม่มีตัวคัดกรองคอยเช็กว่าเวลามัน “ชนกัน” หรือไม่ วันนี้ผมเลยจะมาชวนทุกคนอัปเกรดความอัจฉริยะ ย้ายระบบจองมาไว้บน Web App + Google Sheets แล้วให้ระบบมันเชื่อมโยงกับ Google Calendar เพื่อเช็กคิวว่างและล็อคคิวให้อัตโนมัติแบบ Real-time กันครับ!
🛑 ปัญหาชวนปวดหัว: เมื่อคิวซ้อน เงินและเวลาก็หดหาย
การจองทรัพยากรส่วนกลางแบบเดิมๆ มีช่องโหว่เยอะมากครับ:
- อัปเดตช้า: คนที่อยู่หน้างานไม่รู้ว่าคนอื่นจองไปแล้วหรือยัง
- ไม่มีการตรวจสอบ (No Validation): ระบบแมนนวลไม่สามารถแจ้งเตือนได้ทันทีว่า “เวลานี้มีคนใช้แล้วนะ” จนกว่าจะเกิดปัญหาขึ้นจริง
- ตรวจสอบย้อนหลังยาก: พอมีปัญหา ก็ต้องมานั่งไล่หาว่าใครเป็นคนหยิบกุญแจรถไป หรือใครเริ่มจองก่อน-หลัง
เพื่อแก้ปัญหานี้ เราจำเป็นต้องสร้าง “ผู้คุมกฎดิจิทัล” ที่ทำงานได้อย่างเที่ยงตรงตลอด 24 ชั่วโมงครับ
⚖️ เปรียบเทียบชัดๆ: “จองแบบเดิม” VS “ระบบจองอัจฉริยะ”
เพื่อให้เห็นภาพว่าการนำระบบนี้ไปใช้จะคุ้มค่ากับการลงทุนเวลาแค่ไหน ลองมาดูข้อเปรียบเทียบกันครับ:
| หัวข้อการใช้งาน | ❌ ระบบจองแบบเดิม (Manual / ไลน์กลุ่ม) | ✅ ระบบจองอัจฉริยะ (Web App + Calendar) |
| การป้องกันคิวซ้อน | ทำไม่ได้ ต้องใช้คนคอยตรวจสอบและเสี่ยงผิดพลาด | ระบบบล็อกทันที หากเลือกวัน/เวลาที่มีคนจองไว้แล้ว |
| ความสะดวกในการเช็กคิว | ต้องเดินไปดูที่สมุด หรือเปิดย้อนอ่านแชทไลน์เก่าๆ | เปิดดูผ่านมือถือได้ทุกที่ผ่าน Google Calendar |
| การเก็บสถิติและรายงาน | ต้องมานั่งคัดลอกข้อมูลลงคอมพิวเตอร์ใหม่ตอนสิ้นเดือน | ข้อมูลบันทึกลง Google Sheets อัตโนมัติ นำไปวิเคราะห์ต่อได้เลย |
| ระบบแจ้งเตือน | ต้องโทรตาม หรือพิมพ์บอกกันเอง | ระบบส่งแจ้งเตือนเข้า LINE Messaging API ทันทีเมื่อการจองสำเร็จ |
🛠️ โครงสร้างระบบ: ลดความเสี่ยงการจองซ้อนอย่างไร?
เบื้องหลังของความโปรในโปรเจกต์นี้ เกิดจากการเขียน Google Apps Script ให้ทำหน้าที่เป็น “สมองกล” คอยคุยกันระหว่างหน้าเว็บจองและระบบปฏิทินครับ:
- ดึงข้อมูลคิวปัจจุบัน: เมื่อมีคนเปิดหน้าเว็บขึ้นมา ระบบจะวิ่งไปถาม Google Calendar ก่อนว่า “ในวันที่เลือก มีอีเวนต์ไหนอยู่บ้าง?” แล้วส่งช่วงเวลาที่ถูกจองไปแล้วกลับมาโชว์ให้ผู้ใช้เห็น
- ตรวจสอบเงื่อนไขก่อนบันทึก: ทันทีที่ผู้ใช้กดปุ่ม “ยืนยันการจอง” Script จะทำการเช็กซ้ำอีกรอบ (Double Check) ว่าในช่วงเวลาเสี้ยววินาทีนั้นมีใครตัดหน้าจองไปก่อนหรือเปล่า
- บันทึกข้ามระบบ: หากผ่านเงื่อนไข โค้ดจะสั่งบันทึกรายละเอียดลง Google Sheets (สำหรับเก็บสถิติ) และสร้างนัดหมายลง Google Calendar (เพื่อให้ปฏิทินส่วนกลางอัปเดตทันที)

ลองทำตาม: ระบบจองที่ตรวจเวลาชนก่อนบันทึก
ตัวอย่างนี้ใช้ปฏิทิน Google 1 ปฏิทินต่อห้องประชุม 1 ห้องหรือรถ 1 คัน หน้าเว็บแสดงช่วงที่ถูกจองของวันที่เลือก และฝั่งเซิร์ฟเวอร์ตรวจซ้ำก่อนสร้างนัดหมายทุกครั้ง ทดลองด้วยปฏิทินทดสอบก่อนใช้กับห้องจริง
1. เตรียมปฏิทินและชีต
- ใน Google Calendar สร้างปฏิทินใหม่ เช่น “ห้องประชุมใหญ่” เปิด Settings and sharing ของปฏิทินนั้น แล้วคัดลอก Calendar ID ในหัวข้อ Integrate calendar
- ในชีต ตั้งชื่อแท็บว่า
Bookingsหัวคอลัมน์ 4 ช่อง ได้แก่ เวลาบันทึก ชื่อผู้จอง เริ่ม และสิ้นสุด - เปิด ส่วนขยาย (Extensions) > Apps Script แล้วตรวจ Time zone ใน Project Settings ให้เป็นเวลาประเทศไทย (Asia/Bangkok) เวลาที่ผู้ใช้เลือกบนหน้าเว็บจะได้ตรงกับเวลาในปฏิทิน
2. โค้ดฝั่งเซิร์ฟเวอร์ (Code.gs)
const CALENDAR_ID = 'วาง Calendar ID ของห้องหรือรถ';
const SHEET_NAME = 'Bookings';
function doGet() {
return HtmlService.createHtmlOutputFromFile('index')
.setTitle('จองห้องประชุม')
.addMetaTag('viewport', 'width=device-width, initial-scale=1');
}
function getCalendar_() {
const calendar = CalendarApp.getCalendarById(CALENDAR_ID);
if (!calendar) throw new Error('ไม่พบปฏิทิน ตรวจ CALENDAR_ID อีกครั้ง');
return calendar;
}
function clean_(value, maxLength) {
const text = String(value || '').trim().slice(0, maxLength);
return /^[=+\-@]/.test(text) ? "'" + text : text;
}
function getBusySlots(dateText) {
const dayStart = new Date(dateText + 'T00:00:00');
const dayEnd = new Date(dayStart.getTime() + 24 * 60 * 60 * 1000);
const timeZone = Session.getScriptTimeZone();
return getCalendar_().getEvents(dayStart, dayEnd).map(function (event) {
return Utilities.formatDate(event.getStartTime(), timeZone, 'HH:mm') + '-' +
Utilities.formatDate(event.getEndTime(), timeZone, 'HH:mm');
});
}
function book(form) {
const name = clean_(form.name, 100);
const start = new Date(form.start);
const end = new Date(form.end);
if (!name || isNaN(start) || isNaN(end) || start >= end) {
throw new Error('กรอกชื่อ และเลือกเวลาสิ้นสุดให้อยู่หลังเวลาเริ่ม');
}
const lock = LockService.getScriptLock();
lock.waitLock(10000); // ถ้ามีคนกดจองพร้อมกัน จะเข้าคิวทีละคน รอได้สูงสุด 10 วินาที
try {
const calendar = getCalendar_();
if (calendar.getEvents(start, end).length > 0) {
throw new Error('ช่วงเวลานี้มีการจองแล้ว กรุณาเลือกเวลาอื่น');
}
calendar.createEvent('จองโดย ' + name, start, end);
SpreadsheetApp.getActiveSpreadsheet().getSheetByName(SHEET_NAME)
.appendRow([new Date(), name, start, end]);
return 'จองสำเร็จ ' + Utilities.formatDate(start, Session.getScriptTimeZone(), 'd/M/yyyy HH:mm');
} finally {
lock.releaseLock();
}
}getEvents(start, end) ดึงนัดหมายทุกรายการที่อยู่ในช่วงเวลาที่ขอจอง ถ้ามีแม้แต่รายการเดียวแปลว่าเวลาชนกัน ส่วน LockService ทำให้โค้ดช่วงตรวจและบันทึกทำงานทีละคน จึงกันกรณีสองคนเห็นว่าว่างพร้อมกันแล้วกดจองเวลาเดียวกันได้ ข้อความแจ้งเวลาชนไม่บอกชื่อนัดหมายเดิม เพื่อไม่ให้ข้อมูลการประชุมของคนอื่นหลุดออกไปทางหน้าเว็บ
3. หน้าเว็บ (index.html)
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<h1>จองห้องประชุม</h1>
<form id="booking-form">
<p><input name="name" maxlength="100" placeholder="ชื่อผู้จอง" required></p>
<p>เริ่ม <input type="datetime-local" name="start" required></p>
<p>สิ้นสุด <input type="datetime-local" name="end" required></p>
<p><button type="submit">จอง</button></p>
</form>
<p id="busy"></p>
<p id="message"></p>
<script>
var form = document.getElementById('booking-form');
var button = form.querySelector('button');
var busy = document.getElementById('busy');
var message = document.getElementById('message');
form.start.addEventListener('change', function () {
google.script.run
.withSuccessHandler(function (slots) {
busy.textContent = slots.length ? 'ช่วงที่ถูกจองแล้ว: ' + slots.join(', ') : 'วันที่เลือกยังว่างทั้งวัน';
})
.withFailureHandler(function (error) { busy.textContent = error.message; })
.getBusySlots(form.start.value.slice(0, 10));
});
form.addEventListener('submit', function (event) {
event.preventDefault();
button.disabled = true;
google.script.run
.withSuccessHandler(function (text) { message.textContent = text; form.reset(); button.disabled = false; })
.withFailureHandler(function (error) { message.textContent = error.message; button.disabled = false; })
.book(form);
});
</script>
</body>
</html>เมื่อผู้ใช้เลือกเวลาเริ่ม หน้าเว็บจะถามช่วงที่ถูกจองของวันนั้นมาแสดงก่อน ฟังก์ชัน getBusySlots แปลงเวลาเป็นข้อความก่อนส่งกลับ เพราะ google.script.run ส่งค่าประเภทวันที่ (Date) กลับไปหน้าเว็บโดยตรงไม่ได้
4. Deploy และทดสอบ
Deploy เป็น Web App ตามขั้นตอนในบทความ Google Sheets เป็น Web App เลือก Execute as เป็น Me สคริปต์จะสร้างนัดหมายด้วยสิทธิ์ของเจ้าของปฏิทิน ผู้จองจึงไม่ต้องมีสิทธิ์แก้ไขปฏิทินเอง จากนั้นลองจองช่วงเวลาเดียวกันสองครั้ง ครั้งที่สองต้องขึ้นข้อความว่ามีการจองแล้ว
อ้างอิง: Class Calendar (getEvents, createEvent), Class Lock และ HTML Service: Communicate with Server Functions — ตรวจข้อมูล 18 ตุลาคม 2026
🎯 บทสรุป
การสร้างระบบจองอัจฉริยะไม่ได้ช่วยแค่ลดความขัดแย้งเรื่องการแย่งใช้ทรัพยากรในองค์กรเท่านั้นครับ แต่มันคือการ “สร้างมาตรฐานการทำงานที่เป็นระบบ (Systematic Workflow)” ที่ทำให้องค์กรหรือธุรกิจของคุณดูโปรเฟสชันนัล น่าเชื่อถือ และทำงานได้อย่างลื่นไหล
ลองเอาแนวทางใน EP19 นี้ไปปรับใช้กันดูนะครับ รับรองว่าจะช่วยประหยัดเวลา และลดปัญหาปวดหัวในออฟฟิศไปได้มหาศาลแน่นอน! ถ้าชอบบทความไอทีเข้าใจง่ายแบบนี้ อย่าลืมแชร์ต่อให้เพื่อนร่วมงาน และคอมเมนต์บอกผมใต้โพสต์นี้ด้วยนะครับว่าอยากให้ทริคอะไรใน EP ถัดไป
เปลี่ยนงานวุ่นวาย ให้กลายเป็นระบบอัตโนมัติ





ใส่ความเห็น