跳到主要內容跳到頁尾

Apps Script onEdit:狀態改成已出貨,自動填出貨日

6 分鐘閱讀Lv.2 中級摘要與日期

用出貨單示範簡單觸發器 onEdit:讀事件物件,判斷是不是該動的那一格,再在同一列填入日期。附完整程式與判斷條件的理由。

發布 更新

文章目錄

倉管同事在「出貨單」把狀態改成「已出貨」,出貨日卻常常忘了填。希望狀態一變,同一列的出貨日自己出現。

這件事不用人按按鈕,也不用排程:Apps Script 有一種簡單觸發器 onEdit,有人改了儲存格,Google 就會自動呼叫它。

先看流程

概念示意:使用者在出貨單把 E 欄改成已出貨,Google 自動呼叫 onEdit 並傳入事件物件,判斷函式檢查六個條件,全部成立才在同一列 F 欄填入今天日期。← 左右滑動看完整的圖,點圖可放大

程式要回答的只有一題:這次被改的那一格,是不是我要處理的那一格? 不是就什麼都不做。

先準備

  • 「出貨單」分頁:A1:F1 是表頭,E 欄是狀態(用「插入 → 下拉式選單」設成「待出貨」「已出貨」),F 欄是出貨日。
  • 在這份試算表選「擴充功能 → Apps Script」,把下面三個區塊貼進去並儲存。
  • onEdit 是固定名稱的簡單觸發器,不需要另外建立觸發器。
  • 要測試時,到試算表實際改一格 E 欄才會觸發。在 Apps Script 編輯器直接按「執行」onEdit,e 會是 undefined,只會看到錯誤訊息,不代表程式有問題。

區塊一:把會變的東西放在最上面

程式碼.gs
Apps Script
/**
 * @OnlyCurrentDoc
 */

const SHEET_NAME = "出貨單";
const FIRST_DATA_ROW = 2; // 第 1 列是表頭
const STATUS_COL = 5; // E 欄:狀態
const DATE_COL = 6; // F 欄:出貨日
const DONE_TEXT = "已出貨";
  • 最上面的 @OnlyCurrentDoc 註解,宣告這支程式只會用到目前這份試算表。
  • 分頁名稱、欄位位置、關鍵字集中在這幾行,之後換情境只改這裡。
  • 欄位用數字:E 是第 5 欄、F 是第 6 欄。
  • 第 1 列是表頭,所以資料從第 2 列開始。

區塊二:判斷要不要動

程式碼.gs
Apps Script
// 只在「出貨單」資料列的 E 欄被單格改成「已出貨」,而且 F 欄還是空的時候才回 true
function shouldStampShipDate(info, currentDate) {
  const isTarget = info.sheetName === SHEET_NAME && info.row >= FIRST_DATA_ROW && info.col === STATUS_COL;
  const isSingleCell = info.numRows === 1 && info.numColumns === 1;
  const isEmptyDate = currentDate === "" || currentDate === null || currentDate === undefined;
  return isTarget && isSingleCell && info.value === DONE_TEXT && isEmptyDate;
}
  • 輸入是一包描述「這次編輯」的資料 info,加上 F 欄現有的值;輸出只有 true 或 false。
  • 它不碰試算表,所以可以在 Google 以外直接測。
  • 六個條件要同時成立:在「出貨單」、第 2 列以後、E 欄、只改一格、新值是「已出貨」、F 欄是空的。

區塊三:onEdit 取資料、寫入

程式碼.gs
Apps Script
// 簡單觸發器:使用者編輯儲存格後,Google 會自動呼叫,並傳入事件物件 e
function onEdit(e) {
  const range = e.range;
  const sheet = range.getSheet();
  const info = {
    sheetName: sheet.getName(),
    row: range.getRow(),
    col: range.getColumn(),
    numRows: range.getNumRows(),
    numColumns: range.getNumColumns(),
    value: e.value,
  };
  const dateCell = sheet.getRange(info.row, DATE_COL);
  if (shouldStampShipDate(info, dateCell.getValue())) {
    dateCell.setValue(new Date());
  }
}
  • e 是 Google 傳進來的事件物件,e.range 是被改的範圍,e.value 是改完的值。
  • 先組出 info,再讀同一列 F 欄現有的值,交給判斷函式。
  • 只有回傳 true,才對那一格 setValue(new Date())。
  • new Date() 是日期加時間。F 欄若沒有設定格式,儲存格通常會顯示日期加時間;想只顯示日期,先把 F 欄設成日期格式(格式 → 數字 → 日期)。之後要用日期比對或統計時,用 INT() 取出整數日期。

事件物件 e 有什麼

屬性內容這篇用到嗎
e.range被編輯的儲存格範圍用到,取得分頁、列、欄、大小
e.value編輯後的值,只有改單一儲存格時才有用到
e.oldValue編輯前的值,同樣只有單格;原本空白時是 undefined沒用到
e.source綁定的試算表沒用到
e.user目前使用者,受安全限制,不一定取得沒用到

為什麼要排除多格與覆蓋

  • 多格貼上:一次貼上很多格時,e.value 不會有值,也分不出每一格原本是什麼。保守的做法是整批不動,需要日期時要手動補。
  • 已有日期:狀態從「已出貨」改回「待出貨」再選回「已出貨」時,如果直接填日期,原本的出貨日會被換成今天。F 欄有值就不寫,可以保留第一次的紀錄。
  • 清空:按 Delete 清掉狀態時,新值不會是「已出貨」,自然不會動。
  • 程式自己寫的不會再觸發:腳本用 setValue 寫 F 欄,官方文件說明這不會再觸發 onEdit,所以不會無限循環。

前後對照

下表是示意用的「出貨單」改之前的樣子。假設把 S002 的狀態改成「已出貨」(這張表不會執行程式,改了也不會出現日期):

A2
列 / 欄ABCDEFG
1訂單編號客戶品項數量狀態出貨日
2S001王小明咖啡豆2已出貨2026/10/16
3S002李小華濾紙5待出貨
4S003陳大文手沖壺1待出貨
5S004林小美磨豆機1待出貨
6S005張三咖啡豆3待出貨
7
8

可直接編輯儲存格 • 重新整理即還原

在真正的試算表裡,改完後 S002 的 F 欄會自動出現當天日期(下表是 2026/10/17 當天、F 欄已設成日期格式的結果;沒設格式時會多顯示時間),S001 原本的日期不變;這張表只是預先寫好的結果,不會自己跑程式:

列 / 欄ABCDEF
1訂單編號客戶品項數量狀態出貨日
2S001王小明咖啡豆2已出貨2026/10/16
3S002李小華濾紙5已出貨2026/10/17
4S003陳大文手沖壺1待出貨
5S004林小美磨豆機1待出貨
6S005張三咖啡豆3待出貨

示範試算表

換成你的情境

  • 分頁名稱:SHEET_NAME。
  • 狀態在哪一欄、日期要填哪一欄:STATUS_COL、DATE_COL。
  • 關鍵字:DONE_TEXT,改成「已完成」「已寄出」都可以。
  • 表頭佔幾列:FIRST_DATA_ROW。
1

改成「已完成」填完成日

同一個出貨單,現在要在 E 欄變成「已完成」時,把完成日填在 G 欄(第 7 欄)。先預測:要改哪幾個常數?哪幾個不用改?(E 欄的下拉選單另外要加「已完成」。)

延伸閱讀

說明

這支程式只處理用下拉選單改單一儲存格狀態的情境;貼上多格、清空、改其他欄與其他分頁,都不會寫入日期。簡單觸發器不能使用需要授權的服務(例如寄信),執行時間上限 30 秒。

分享:
#Apps Script#onEdit#觸發器#事件物件
喜特先生 Mr. Sheet

喜特先生 Mr. Sheet

數據分析師/商業分析師

八年工作經驗,跨不同業界解決數據需求。做過的案例都整理在作品集。

接下來可以

相關文章

查看所有文章

留言討論

共 0 則留言

訂閱電子報,新文章上線就通知你

免費,隨時可取消。

送出即表示同意服務條款與隱私權政策。