ซีรีส์ Apps Script ด้วย AI · ตอนที่ 1 จาก 3
Apps Script คืออะไร: ทำเมนูของตัวเองใน Google ชีต และอ่านหน้าขอสิทธิ์ให้เป็น
21 ต.ค. 2569 · อ่าน 8 นาที
Apps Script คือโปรแกรมเล็กๆ ที่ฝังในไฟล์ Google ชีต ทำให้งานที่กดซ้ำทุกวันเหลือคลิกเดียว ตอนแรกของซีรีส์ Apps Script ด้วย AI ลองทำเมนูเรียงออเดอร์และไฮไลต์คนที่ยังไม่จ่ายกับร้านขนมสมมติ รันจริงในชีต พร้อมบรรทัดเดียวที่ทำให้สคริปต์ขอสิทธิ์แค่ไฟล์เดียวและหน้าเตือน "Google hasn't verified this app" ไม่ขึ้น และกฎ 2 ข้อก่อนกดอนุญาต

ทุกเช้าเจ้าของร้านขนมเปิดชีตออเดอร์ เรียงตามวันส่ง แล้วไล่ดูว่าใครยังไม่จ่าย ทำวันละไม่กี่นาที แต่ทำทุกวัน
ตอนแรกของซีรีส์ "Apps Script ด้วย AI" จะเปลี่ยนงานนี้ให้เหลือคลิกเดียว ด้วยเมนูที่เราสร้างเองบนแถบเมนูของ Google ชีต ไม่ต้องเขียนโปรแกรมเป็น แต่ต้องอ่านหน้าขอสิทธิ์เป็น ซึ่งเป็นเรื่องที่สำคัญที่สุดของตอนนี้
ข้อมูล ณ ตุลาคม 2569 ผลในบทความนี้มาจากการลองจริงในบัญชี Google ของเรา กับร้านขนมบ้านเนย ซึ่งเป็นร้านสมมติ หน้าจอในภาพเป็นเมนูภาษาอังกฤษ ถ้าบัญชีของคุณตั้งเป็นภาษาไทย ชื่อเมนูจะเป็นภาษาไทยแทน แต่อยู่ตำแหน่งเดิม
Apps Script คืออะไร
Apps Script คือโปรแกรมเล็กๆ ที่ฝังอยู่ในไฟล์ Google ชีต เอกสาร หรือฟอร์ม และรันบนเครื่องของ Google ใช้ได้ฟรีกับบัญชี Google ทั่วไป
มันทำได้มากกว่าสูตร เพราะสูตรคำนวณได้แค่ในช่องของตัวเอง ส่วนสคริปต์สั่งงานทั้งไฟล์ได้
- เพิ่มเมนูและปุ่ม เรียงข้อมูล ระบายสี ย้ายแถว (ตอนนี้)
- ส่งอีเมล เมื่อมีคนกรอกฟอร์ม (ตอนที่ 4)
- สร้างเอกสาร จากข้อมูลทีละแถว เช่น ใบเสนอราคา (ตอนที่ 5)
- ทำงานเองตามเวลา แม้ไม่มีใครเปิดไฟล์ (ตอนที่ 6)
- เปลี่ยนชีตเป็นหน้าเว็บ (ตอนที่ 8)
โค้ดเป็นภาษา JavaScript ซึ่งตลอดซีรีส์เราให้ AI เขียน งานของเราคืออ่านให้เข้าใจพอจะรู้ว่ามันทำอะไร แล้วตรวจผล
ลองทำเมนู "🧁 ร้านขนม" สำหรับเรียงออเดอร์และไฮไลต์คนที่ยังไม่จ่าย
ไฟล์ตัวอย่าง: ดาวน์โหลด "ชีตตัวอย่าง Apps Script ตอน 1: ออเดอร์ร้านขนม" ได้ที่หน้าเทมเพลต (สมัครสมาชิกฟรีก่อนดาวน์โหลด) ไฟล์เป็น Excel ต้องเปลี่ยนเป็น Google ชีตก่อนใช้ ดังนี้
- อัปไฟล์ขึ้น Google Drive แล้วเปิดไฟล์
- กด File › Save as Google Sheets ระบบจะเปิดไฟล์ใหม่ที่เป็น Google ชีต ใช้ไฟล์ใหม่นี้ในทุกขั้นต่อจากนี้
- กด File › Settings แล้วตั้งช่อง Locale เป็น Thailand ตามที่เราใช้ทดสอบ
ชีตตัวอย่างมีแท็บชื่อ "ออเดอร์" แถวแรกเป็นหัวตาราง (เลขออเดอร์ วันที่สั่ง วันส่ง ชื่อลูกค้า เบอร์โทร สินค้า จำนวน ราคารวม จ่ายแล้ว สถานะ) และ 1 แถวคือ 1 ออเดอร์ ถ้าจะลองกับชีตของคุณเอง ให้ทำสำเนาก่อนทุกครั้ง
- เปิดไฟล์ชีต แล้วกดเมนู Extensions › Apps Script ระบบจะเปิดแท็บใหม่ที่มีไฟล์
Code.gs - ตั้งชื่อโปรเจกต์ที่มุมซ้ายบน เช่น "เมนูร้าน" ชื่อนี้จะไปโผล่ในหน้าขอสิทธิ์
- ลบโค้ดเดิมทั้งหมด วางโค้ดข้างล่างแทน แล้วกดบันทึก (ไอคอนแผ่นดิสก์)
- ที่ช่องเลือกฟังก์ชันด้านบน เลือก
sortByDueDateแล้วกด Run - ครั้งแรกจะมีหน้าขอสิทธิ์ อ่านหัวข้อถัดไปก่อนกด
- กลับไปหน้าชีต รีเฟรชหนึ่งครั้ง รอ 2–3 วินาที เมนู "🧁 ร้านขนม" จะขึ้นต่อจาก Help
/** @OnlyCurrentDoc */
const SHEET_NAME = 'ออเดอร์';
const HIGHLIGHT = '#F6D5C8'; // สีส้มอ่อน
// onOpen ทำงานเองทุกครั้งที่เปิดไฟล์ → เพิ่มเมนูบนแถบด้านบน
function onOpen() {
SpreadsheetApp.getUi()
.createMenu('🧁 ร้านขนม')
.addItem('เรียงตามวันส่ง', 'sortByDueDate')
.addItem('ไฮไลต์ออเดอร์ที่ยังไม่จ่าย', 'highlightUnpaid')
.addItem('ล้างสีไฮไลต์', 'clearHighlight')
.addToUi();
}
// หาเลขคอลัมน์จาก "ชื่อหัวตาราง" — ถ้ามีคนแทรกคอลัมน์ สคริปต์ยังหาเจอ
function columnOf_(sheet, headerName) {
const headers = sheet.getRange(1, 1, 1, sheet.getLastColumn()).getValues()[0];
const index = headers.indexOf(headerName);
if (index === -1) throw new Error('ไม่เจอหัวตาราง "' + headerName + '" ในแถวที่ 1');
return index + 1;
}
function ordersSheet_() {
const sheet = SpreadsheetApp.getActive().getSheetByName(SHEET_NAME);
if (!sheet) throw new Error('ไม่เจอแท็บชื่อ "' + SHEET_NAME + '"');
return sheet;
}
function sortByDueDate() {
const sheet = ordersSheet_();
const lastRow = sheet.getLastRow();
if (lastRow < 3) return;
// เรียงเฉพาะแถวข้อมูล (แถว 2 ลงไป) — หัวตารางอยู่ที่เดิม
sheet.getRange(2, 1, lastRow - 1, sheet.getLastColumn())
.sort({ column: columnOf_(sheet, 'วันส่ง'), ascending: true });
}
function highlightUnpaid() {
const sheet = ordersSheet_();
const lastRow = sheet.getLastRow();
if (lastRow < 2) return;
const paidCol = columnOf_(sheet, 'จ่ายแล้ว');
const paid = sheet.getRange(2, paidCol, lastRow - 1, 1).getValues();
let count = 0;
paid.forEach(function (row, i) {
if (row[0] !== true) { // TRUE = จ่ายแล้ว
sheet.getRange(i + 2, 1, 1, sheet.getLastColumn()).setBackground(HIGHLIGHT);
count++;
}
});
SpreadsheetApp.getActive().toast('ยังไม่จ่าย ' + count + ' ออเดอร์', '🧁 ร้านขนม');
}
function clearHighlight() {
const sheet = ordersSheet_();
const lastRow = sheet.getLastRow();
if (lastRow < 2) return;
sheet.getRange(2, 1, lastRow - 1, sheet.getLastColumn()).setBackground(null);
}4 จุดในโค้ดที่ควรอ่านให้เข้าใจ
onOpenเป็นชื่อพิเศษ Google จะเรียกเองทุกครั้งที่เปิดไฟล์ เราใช้มันสร้างเมนู แต่ละaddItemคือ "ชื่อที่โชว์บนเมนู" คู่กับ "ฟังก์ชันที่จะรัน"columnOf_หาคอลัมน์จากชื่อหัวตาราง ไม่ใช่จากตำแหน่ง เราลองแทรกคอลัมน์ว่างก่อน "วันส่ง" แล้วกดเรียงใหม่ ก็ยังเรียงถูก ถ้าเขียนแบบ "คอลัมน์ที่ 3" ตรงๆ สคริปต์จะเรียงผิดคอลัมน์ทันทีที่มีคนแทรกคอลัมน์throw new Error(...)ถ้าหาแท็บหรือหัวตารางไม่เจอ ให้หยุดพร้อมบอกว่าหาอะไรไม่เจอ ดีกว่าทำงานผิดที่แบบเงียบๆ/** @OnlyCurrentDoc */บรรทัดแรก บอก Google ว่าสคริปต์นี้ขอแตะแค่ไฟล์นี้ ซึ่งเปลี่ยนหน้าขอสิทธิ์ไปเลย อธิบายในหัวข้อถัดไป
อ่านหน้าขอสิทธิ์ให้เข้าใจก่อนกดอนุญาต
ครั้งแรกที่กด Run จะมีกล่อง "Authorization required" ในหน้าเขียนโค้ด แปลว่าสคริปต์ต้องได้รับอนุญาตก่อน กด Review permissions แล้วเลือกบัญชี
หน้าที่ขึ้นต่อจากนั้น ขึ้นกับว่าสคริปต์ขอสิทธิ์มากแค่ไหน เราลองโค้ดเดียวกัน 2 แบบ ต่างกันแค่บรรทัดแรก
แบบที่มี @OnlyCurrentDoc (โค้ดในบทความนี้)
ขึ้นหน้ารายการสิทธิ์ทันที มีข้อเดียว
View and manage spreadsheets that this application has been installed in.
แปลว่า ดูและจัดการได้เฉพาะสเปรดชีตที่ติดตั้งสคริปต์นี้ ในบัญชีที่เราทดสอบ ไม่มีหน้าเตือนอะไรเพิ่ม
แบบที่ไม่มีบรรทัดนั้น
ก่อนถึงหน้ารายการสิทธิ์ จะเจอหน้า "Google hasn't verified this app" บอกว่าแอปขอเข้าถึงข้อมูลสำคัญ และ developer ยังไม่ได้ส่งให้ Google ตรวจ ต้องกด Advanced แล้วกด "Go to (ชื่อโปรเจกต์) (unsafe)" ถึงจะไปต่อได้
พอไปถึงหน้ารายการสิทธิ์ สิทธิ์ที่ขอคือ
See, edit, create, and delete all your Google Sheets spreadsheets.
แปลว่า ดู แก้ สร้าง และลบสเปรดชีตทุกไฟล์ในบัญชี ทั้งที่เมนูของเราแค่เรียงแถวในไฟล์เดียว
บรรทัดเดียวทำให้สิทธิ์แคบลงจากทุกไฟล์ในบัญชี เหลือไฟล์เดียว นิสัยที่ควรติดตัว: ทุกครั้งที่ให้ AI เขียนสคริปต์ที่แตะแค่ไฟล์เดียว ให้สั่งใส่ /** @OnlyCurrentDoc */ ไว้บรรทัดแรก
กฎ 2 ข้อก่อนกด Continue
กดอนุญาตได้เมื่อครบ 2 ข้อเท่านั้น
- คุณอ่านโค้ดแล้ว และรู้คร่าวๆ ว่ามันทำอะไร (ข้อนี้สำคัญที่สุด)
- สิทธิ์ที่ขอตรงกับงาน เช่น เมนูเรียงแถวไม่ควรขอส่งอีเมล
ไม่มีหน้าเตือนไม่ได้แปลว่าปลอดภัย สิทธิ์ "จัดการสเปรดชีตไฟล์นี้" ก็ลบข้อมูลทั้งไฟล์ได้ ถ้าโค้ดเขียนให้ลบ
ถ้าเจอหน้า "hasn't verified" ให้ดูอีเมลในวงเล็บหลังคำว่า developer ตอนเราทดสอบ มันคืออีเมลของบัญชีเราเอง ทั้งที่โค้ดนั้น AI เป็นคนเขียน เราแค่วางลงไป ถ้าเป็นอีเมลของคนที่คุณไม่รู้จัก ให้กด BACK TO SAFETY ทันที ถ้าเป็นอีเมลของคุณเอง ก็ยังต้องอ่านโค้ดตามข้อ 1
ไฟล์ที่คนอื่นส่งมา สคริปต์จะติดมากับไฟล์ด้วย เราลองทำสำเนาไฟล์ที่มีสคริปต์ สคริปต์ก็ติดมาในสำเนา และเพราะมันขอสิทธิ์แค่ไฟล์เดียว จึงไม่มีหน้าเตือนให้ดูอีเมลเลย ก่อนกด Run หรือกดเมนูแปลกๆ ในไฟล์ที่ได้มา ให้เปิด Extensions › Apps Script อ่านโค้ดก่อนทุกครั้ง
ถ้าสคริปต์ขอหลายสิทธิ์ หน้ารายการสิทธิ์จะมีช่องติ๊กให้เลือกทีละข้อ เช่น ในตอนที่ 3 สคริปต์ที่ AI เขียนขอเพิ่มอีกข้อว่า "Allow this application to run when you are not present" คือให้ทำงานเองตอนเราไม่อยู่ ถ้าเราไม่ได้ขอให้มันตั้งเวลา สิทธิ์ข้อนี้คือสัญญาณให้กลับไปอ่านโค้ด
สคริปต์ที่คุณอนุญาตทำงานด้วยสิทธิ์ของบัญชีคุณ ถ้ามันได้สิทธิ์ส่งอีเมล มันจะส่งอีเมลในนามคุณได้
ผลจริงหลังรีเฟรชชีต
หลังรีเฟรชชีต เมนู "🧁 ร้านขนม" ขึ้นบนแถบเมนู
- เรียงตามวันส่ง: ออเดอร์ที่ต้องส่งก่อนขึ้นบนสุด หัวตารางอยู่ที่เดิม
- ไฮไลต์ออเดอร์ที่ยังไม่จ่าย: 5 แถวเปลี่ยนเป็นสีส้ม และมีข้อความมุมขวาล่างว่า "ยังไม่จ่าย 5 ออเดอร์"
- ล้างสีไฮไลต์: สีหายหมด
ตั้งแต่เปิด Apps Script จนกดเมนูได้ คนที่ลองให้เราใช้ราว 5–10 นาที ไม่นับเวลาอ่านหน้าขอสิทธิ์ ครั้งแรกให้เผื่อเวลาอ่านหน้าขอสิทธิ์ไว้ด้วย ครั้งต่อไปแค่เปิดไฟล์ เมนูก็ขึ้นเอง
ถ้าเมนูไม่ขึ้น หรือเจอ error
- เมนูไม่ขึ้น รีเฟรชชีตอีกครั้ง แล้วรอสักครู่ เมนูจะขึ้นหลังไฟล์โหลดเสร็จ
- error ว่าไม่เจอแท็บ หรือไม่เจอหัวตาราง ชื่อในโค้ดต้องตรงกับชีตทุกตัวอักษร รวมถึงวรรค แก้ที่บรรทัด
SHEET_NAMEหรือแก้ชื่อหัวตารางในชีต - เปิดหลายบัญชี Google ในหน้าต่างเดียว Apps Script มักเปิดผิดบัญชี ใช้โปรไฟล์เบราว์เซอร์แยก หรือหน้าต่างไม่ระบุตัวตน
ตอนถัดไป: ทำไมชีตที่ดูปกติ สคริปต์ถึงอ่านผิด?
สคริปต์ตอนนี้เราเขียนให้ พออยากได้สคริปต์ของงานตัวเอง ก็แค่ให้ AI เขียน แต่ AI มองไม่เห็นชีตของคุณ และชีตแบบที่คนใช้กันจริงมักมีเซลล์ผสาน หัวตาราง 2 ชั้น หรือวันที่ที่พิมพ์เป็นข้อความ ซึ่งทำให้สคริปต์อ่านผิดทั้งที่ตาเราเห็นว่าปกติ
ตอนถัดไป เราจะเอาชีตยุ่งๆ แบบนั้นมาตรวจด้วยสคริปต์ตัวที่สอง ซึ่งเจอปัญหา 10 จุด แล้วดูว่าต้องแก้อะไรก่อนให้ AI เขียนโค้ด
อาทิตย์ละสกิล เดี๋ยวก็เก่ง