2025年11月8日 星期六

【AI教學】取代 formLimiter!用 Gemini 生成 Google 表單報名限制人數與開始時間的程式碼

過去,許多人依賴 Google 表單的 formLimiter 外掛來設定報名人數上限或問卷的截止時間。然而,隨著 formLimiter 開始收費,我們該如何找到替代方案呢?別擔心!現在 AI 非常方便,我們可以透過像 Gemini 這樣強大的人工智慧,客製化我們需要的功能,甚至比以前更強大!

這篇教學將帶您一步步了解,如何透過與 AI 對話,產生一段 Google Apps Script 程式碼,為您的 Google 表單打造一個具備以下功能的客製化報名系統:

  • 指定開始時間:表單會在您設定的特定日期和時間自動開放。

  • 限制報名人數:當報名人數達到上限時,表單會自動關閉。

  • 動態顯示狀態

    • 報名開始前:顯示「表單預計於 [指定時間] 開放」。

    • 開放報名中:即時顯示「總名額、已報名人數、剩餘名額」。

    • 報名額滿後:顯示「報名已額滿或活動已結束」。

與 AI 的溝通歷程

一切都始於一個簡單的問題。我直接詢問 Gemini,formLimiter 開始收費後,是否有替代方案。AI 建議使用 Google Apps Script (GAS) 是個好方法。

接著,我提出我的具體需求,整個過程就像與一位程式設計師對話,不斷地提出想法並進行修正:

  1. 初步請求:我想要一個可以限制人數、指定開始時間的腳本。

  2. 程式碼優化:AI 產生的第一版程式碼需要手動貼上表單 ID,我請它修改成「在同一個表單中,可以自己抓到自己的表單ID嗎?」。 Gemini 理解了這是「Bound Script」的概念,並優化了程式碼。

  3. 增加動態說明:我希望能在表單說明中,顯示目前剩餘的名額,例如:「人數限制 X 人,目前已報名 Y 人,還剩下 Z 人」。

  4. 區分表單狀態:最後,我希望表單能有三種不同的狀態訊息:報名開始前、報名中、已額滿。

經過幾輪的溝通,Gemini 最終產生了我們需要的完整程式碼。這個過程也證明了,即使您不是程式專家,也能透過清晰的描述,引導 AI 完成複雜的任務。

您可以透過此連結查看我與 Gemini 的完整對話過程:
https://gemini.google.com/share/4ca6fa9e9083e1

最終程式碼 (Google Apps Script)

這就是 AI 最終為我們產生的程式碼。您可以直接複製並貼到您的表單指令碼編輯器中使用。

JavaScript
/**
 * v20251108
 * 變數設定區
 */
// 1. 設定 回應數量上限
var RESPONSE_LIMIT = 3; // 額滿人數 (請修改為您的需求)

// 2. 設定 表單原始說明文字 (不包含報名狀態)
var ORIGINAL_DESCRIPTION = "歡迎參加本次活動,請填寫以下資訊。"; // 表單的固定說明 (請修改為您的需求)

// 3. 設定 表單「尚未開始」的訊息
//    {startTime} 會被自動替換為下面的開始時間
var MSG_PENDING = "表單預計於 {startTime} 開放,敬請期待。";

// 4. 設定 表單「開放中」的訊息
//    {originalDescription} 會被替換為原始說明
//    {responseLimit}, {responseCount}, {remaining} 會被替換為對應的數字
var MSG_OPEN_PATTERN = "{originalDescription}\n\n報名狀態:(人數限制 {responseLimit} 人, 已報名 {responseCount} 人, 剩餘名額 {remaining})";

// 5. 設定 表單「已關閉」的訊息
var MSG_CLOSED = "報名名額已滿或活動已結束,感謝您的參與。";

// 6. 設定 表單預計開放時間 (格式: YYYY-MM-DD HH:MM)
var START_TIME = "2025-11-08 14:30"; // 表單開放時間 (請修改為您的需求)

// 7. 設定 額滿時通知的 Email 地址
var NOTIFY_EMAIL = "your-email@gmail.com"; // 額滿時通知的信箱 (請修改為您的需求)

// --- 以下為程式碼,通常不需修改 ---
var STATE_PROPERTY_KEY = "FORM_STATE"; // 用於儲存狀態的屬性鍵

/**
 * 輔助函數:取得當前的表單物件
 */
function getThisForm() {
  return FormApp.getActiveForm();
}

/**
 * 核心函數:更新表單說明
 */
function updateFormDescription(form) {
  try {
    var state = PropertiesService.getDocumentProperties().getProperty(STATE_PROPERTY_KEY);
    var newDescription = "";
    
    switch (state) {
      case "PENDING":
        newDescription = MSG_PENDING.replace('{startTime}', START_TIME);
        break;
        
      case "OPEN":
        var responseCount = form.getResponses().length;
        var remaining = RESPONSE_LIMIT - responseCount;
        if (remaining < 0) {
          remaining = 0;
        }
        newDescription = MSG_OPEN_PATTERN
          .replace('{originalDescription}', ORIGINAL_DESCRIPTION)
          .replace('{responseLimit}', RESPONSE_LIMIT)
          .replace('{responseCount}', responseCount)
          .replace('{remaining}', remaining);
        break;
        
      case "CLOSED":
        newDescription = MSG_CLOSED;
        break;
        
      default: // 如果沒有狀態,預設為 PENDING
        setFormToPending(); 
        return;
    }
    
    form.setDescription(newDescription);
    Logger.log("表單說明已更新為狀態: " + state);
    
  } catch (e) {
    Logger.log("更新表單說明時發生錯誤: " + e.message);
  }
}


/**
 * 觸發器函數 (時間驅動):開啟表單
 */
function openForm() {
  try {
    var form = getThisForm();
    form.setAcceptingResponses(true);
    
    // 將狀態設定為 OPEN
    PropertiesService.getDocumentProperties().setProperty(STATE_PROPERTY_KEY, "OPEN");
    
    // 更新說明文字
    updateFormDescription(form);
    
    Logger.log("表單已開啟並接受回應。");
    
  } catch (e) {
    Logger.log("開啟表單時發生錯誤: " + e.message);
  }
}

/**
 * 觸發器函數 (提交時):檢查回應數量
 */
function checkResponseLimit() {
  try {
    var form = getThisForm();
    var responseCount = form.getResponses().length;
    
    Logger.log("目前回應數: " + responseCount + " / " + RESPONSE_LIMIT);
    
    if (responseCount >= RESPONSE_LIMIT) {
      // 1. 將狀態設定為 CLOSED
      PropertiesService.getDocumentProperties().setProperty(STATE_PROPERTY_KEY, "CLOSED");
      
      // 2. 設定表單關閉後的訊息
      form.setConfirmationMessage(MSG_CLOSED);
      
      // 3. 關閉表單
      form.setAcceptingResponses(false);
      Logger.log("已達人數上限 " + RESPONSE_LIMIT + ",表單已關閉。");
      
      // 4. 發送郵件通知
      var userEmail = NOTIFY_EMAIL;
      if (userEmail) {
          var subject = "Google 表單 [" + form.getTitle() + "] 已達報名人數上限";
          var body = "您的表單 '" + form.getTitle() + "' 已達到 " + responseCount + " 個回應的上限,現已自動關閉。";
          MailApp.sendEmail(userEmail, subject, body);
      }
      
    } else {
       // 如果還沒額滿,僅更新說明
       updateFormDescription(form);
    }
  } catch (e) {
    Logger.log("檢查回應數量時發生錯誤: " + e.message);
  }
}

/**
 * 初始化函數 (手動執行一次):將表單設為「尚未開始」狀態
 */
function setFormToPending() {
  try {
    var form = getThisForm();
    
    // 1. 將狀態設定為 PENDING
    PropertiesService.getDocumentProperties().setProperty(STATE_PROPERTY_KEY, "PENDING");
    
    // 2. 設定表單關閉時的預設訊息
    form.setConfirmationMessage(MSG_CLOSED);
    
    // 3. 關閉表單
    form.setAcceptingResponses(false);
    
    // 4. 更新說明文字
    updateFormDescription(form);
    
    Logger.log("表單已初始化為 PENDING (尚未開始) 狀態。");
    
  } catch (e) {
    Logger.log("設定 PENDING 狀態時發生錯誤: " + e.message);
  }
}

如何設定?五個步驟搞定!

  1. 進入指令碼編輯器

    • 在您的 Google 表單編輯頁面,點擊右上角的「更多」圖示 (三個點)。

    • 選擇「指令碼編輯器」。

  2. 貼上與修改程式碼

    • 將編輯器中原有的程式碼全部刪除。

    • 將上方提供的完整程式碼複製並貼上。

    • 務必修改開頭「變數設定區」的內容,例如:報名人數上限 (RESPONSE_LIMIT)、表單開放時間 (START_TIME) 以及您自己的 Email (NOTIFY_EMAIL)。

  3. 儲存專案

    • 點擊上方的「儲存專案」圖示。

    • 為您的專案命名,例如「香純滴雞精團購表單」。

  4. 設定觸發條件 (Triggers)

    • 點擊左側的「觸發條件」圖示 (鬧鐘圖示)。

    • 點擊右下角的「+ 新增觸發條件」。

    • 您需要設定兩個觸發條件

      • 觸發條件一 (自動開放表單)

        • 要執行的功能:選擇 openForm

        • 選取活動來源:選擇 時間驅動

        • 選取時間型觸發條件類型:選擇 特定日期和時間

        • 輸入您希望表單開放的日期與時間 (需與程式碼中的 START_TIME 相同)。

        • 點擊「儲存」。

      • 觸發條件二 (檢查人數上限)

        • 點擊「+ 新增觸發條件」。

        • 要執行的功能:選擇 checkResponseLimit

        • 選取活動來源:選擇 來自表單

        • 選取活動類型:選擇 提交表單時

        • 點擊「儲存」。

  5. 初始化表單狀態 (只需做一次)

    • 回到「編輯器」頁面。

    • 在頂端的功能選單中,選擇 setFormToPending

    • 點擊旁邊的「執行」按鈕。

    • 第一次執行時,Google 會要求您「審查權限」,請依照指示點擊「允許」,授權指令碼執行。

    • 執行完畢後,您的表單就會進入「尚未開始」的狀態。

完成以上步驟後,您的客製化報名系統就大功告成了!它會安靜地等待您設定的時間到來,然後自動為您處理報名的一切。這就是善用 AI 提升工作效率的最佳範例!

 



沒有留言:

張貼留言

注意:只有此網誌的成員可以留言。

【AI教學】取代 formLimiter!用 Gemini 生成 Google 表單報名限制人數與開始時間的程式碼

過去,許多人依賴 Google 表單的  formLimiter  外掛來設定報名人數上限或問卷的截止時間。然而,隨著  formLimiter  開始收費,我們該如何找到替代方案呢?別擔心!現在 AI 非常方便,我們可以透過像 Gemini 這樣強大的人工智慧,客製化我們需要的...