擔任資訊組長前的上一個行政工作是訓育組,
當時學校社團並沒有那麼多,反觀現在學生真的很幸福,
但社團愈多就表示承辦的訓育組長工作就會愈繁重!
此時如果沒有一個好用的調查系統,那對承辦人來說真的會是一個問題。
還好現在有好用的 Google Workspace for Education 可以運用,
用 Google 表單的好處是原本就可以限制校內網域帳號和可否重複報名。
如果再加上 Google Apps Script 的加持那就真的無所不能了。
快來看看如何運用 生成式 AI 設定 名額 和 時間限制 的報名表吧!
這次運用了 Google表單(使者介面) + 試算表(基本資料) 來設計這個報名表:
1️⃣ 請用下拉式選單設定表單社團選項:如果使用者報名就會扣除一個名額,名額都報名完該選項就會消失,使用者就無法報名以達到名額限制。
2️⃣ 因為我這邊 GAS 程式將社團下拉式選項設定在第三個題目(報名表D欄) 這邊要留意!不然就是表單設計後記得把它移動到 D欄 的位置
3️⃣ 基本資料:這個工作表可以填入社團名稱和最大人數,因為 GAS 程式中是設定梯次和社團名稱對應,所以這邊梯次名稱序號還是需要
4️⃣ 開放、關閉時間格式:2025/02/1 10:00
5️⃣ 記得將 表單ID 和 試算表ID 替換成自己的版本

function onOpen() {
FormApp.getUi()
.createMenu('🎯更新表單')
.addItem('🚀更新表單', 'updateForm')
.addToUi();
}
function updateForm() {
var formId = '你的Google表單ID'; // 替換為你的表單 ID
var spreadsheetId = '你的Google試算表ID'; // 替換為你的試算表 ID
var questionTitle = "選擇梯次"; // 這裡可修改成你的問題名稱
var form = FormApp.openById(formId);
var ss = SpreadsheetApp.openById(spreadsheetId);
var dataSheet = ss.getSheetByName('基本資料'); // 注意事算表名稱|梯次&人數上限&開始/結束時間
var registrationSheet = ss.getSheetByName('報名記錄'); // 注意事算表名稱|參加者報名情況
if (!dataSheet || !registrationSheet) {
Logger.log("⚠️ 工作表名稱錯誤,請確認 '基本資料' 和 '報名記錄' 是否存在");
return;
}
var workshopData = dataSheet.getDataRange().getValues();
var registrationData = registrationSheet.getDataRange().getValues();
if (workshopData.length < 2) {
Logger.log("⚠️ 基本資料工作表無資料,請確認是否已輸入梯次名稱和人數上限");
return;
}
if (registrationData.length < 2) {
Logger.log("⚠️ 報名記錄工作表無資料,將視為無人報名");
}
var workshopInfo = {}; // 存放梯次名稱與人數
var nameMapping = {}; // A 欄(原始名稱)對應 C 欄(標準名稱)
var startTime, endTime;
for (var i = 1; i < workshopData.length; i++) {
var originalName = (workshopData[i][0] || "").trim().toLowerCase(); // A 欄
var maxParticipants = parseInt(workshopData[i][1], 10); // B 欄
var standardName = (workshopData[i][2] || "").trim().toLowerCase(); // C 欄(標準名稱)
// 讀取填報開始/結束時間
if (i == 1) {
// 讀取填報開始/結束時間
var startTime = workshopData[1][3]; // D 欄:開始時間 2025/02/1 10:00
var endTime = workshopData[1][4]; // E 欄:結束時間 2025/02/10 10:00
var currentTime = new Date(); // 取得當前時間
}
if (originalName && standardName && !isNaN(maxParticipants)) {
nameMapping[originalName] = standardName;
workshopInfo[standardName] = { max: maxParticipants, count: 0 };
}
}
if (startTime) {
startTime = new Date(startTime);
}
if (endTime) {
endTime = new Date(endTime);
}
Logger.log("📆 填報開始時間:" + startTime);
Logger.log("⏳ 填報結束時間:" + endTime);
Logger.log("🕒 當前時間:" + currentTime);
// **檢查填報時間**
if (startTime && currentTime < startTime) {
Logger.log("🚫 尚未到填報時間,關閉表單填報");
form.setAcceptingResponses(false);
return;
}
if (endTime && currentTime > endTime) {
Logger.log("🚫 已超過填報結束時間,關閉表單填報");
form.setAcceptingResponses(false);
return;
}
// 如果時間有效,開啟表單
form.setAcceptingResponses(true);
Logger.log("✅ 開放填報");
// 計算報名人數
for (var i = 1; i < registrationData.length; i++) {
var workshop = String(registrationData[i][3] || "").trim().toLowerCase(); // 確保 workshop 為字串
workshop = workshop.replace(/\s*\(.*?\)\s*/g, ""); // 移除 "(還有 X 名額)" 的部分
// 如果 D 欄的名稱是原始名稱,就轉換為標準名稱
if (nameMapping[workshop]) {
workshop = nameMapping[workshop];
}
if (workshop && workshopInfo.hasOwnProperty(workshop)) {
workshopInfo[workshop].count++;
} else if (workshop) {
Logger.log("⚠️ 找不到對應梯次:" + workshop);
}
}
Logger.log("📊 梯次報名狀況:" + JSON.stringify(workshopInfo));
// 更新 Google 表單的選項
var items = form.getItems();
var targetItem = items.find(item => item.getTitle().trim() === questionTitle); // 確保選對題目
if (!targetItem) {
Logger.log("⚠️ 找不到 '" + questionTitle + "' 題目,請確認表單是否有該選項");
return;
}
var listItem = targetItem.asListItem();
var choices = [];
Object.keys(workshopInfo).forEach(function(option) {
var max = workshopInfo[option].max;
var count = workshopInfo[option].count;
var available = max - count;
if (available > 0) {
choices.push(option + ' (剩餘 ' + available + ' 名額)');
}
});
if (choices.length === 0) {
choices.push('所有梯次已額滿');
}
Logger.log("✅ 更新表單選項:" + JSON.stringify(choices));
listItem.setChoiceValues(choices);
}
// 表單提交時自動執行
function onFormSubmit(e) {
updateForm();
}
6️⃣ 設定好表單的 Apps Script 後還需要設定二個觸發條件
6-1、觸發條件1:提出表單後執行 updateForm 程式
- 選擇您要執行的功能 - onFormSumit
- 將會執行的部署作業 - 上端
- 選取活動來源 - 表單
- 選取活動類型 - 提交表單時
- 錯誤通知設定 - 每天通知我

6-2、觸發條件2:有設定開放和停止時間,所以需要每分鐘都檢查程式設定的時間
- 選擇您要執行的功能 - updateForm
- 將會執行的部署作業 - 上端
- 選取活動來源 - 時間驅動
- 選取時間型觸發條件類型 - 分鐘計時器
- 選取分鐘間隔 - 每分鐘
- 錯誤通知設定 - 每天通知我

7️⃣ 全部設定好後 再發佈表單後,就可以 🎯更新表單 ➜ 試算表社團資料到表單中

快來試試吧~

沒有留言:
張貼留言
歡迎大家一起留言討論!