4520 字
23 分鐘
Google Apps Script × Sheets 實戰指南:從側邊欄到 Web App 部署

前言#

在企業內部工具開發中,Google Sheets 結合 Apps Script 是一個低成本、高效率的解決方案。本文將從實際專案出發,講解如何建立一套完整的商品資料管理系統,並進階部署成獨立的 Web App。

目標讀者#

  • 有基礎 JavaScript 經驗的前端開發者
  • 需要快速建立內部工具的 PM 或開發者
  • 想了解 Apps Script 部署機制的人

你將學到#

  • Apps Script 與 Sheets 的互動機制
  • Trigger(觸發器)的種類與使用時機
  • 側邊欄、Modal 等 UI 元件開發
  • 權限與授權的設計考量
  • Web App 部署與常見問題排解

一、專案架構概覽#

1.1 系統組成#

┌─────────────────────────────────────────────────────┐
│ Google Sheets │
│ ┌─────────────────────────────────────────────────┐│
│ │ 資料儲存(多分頁支援) ││
│ │ A: 編號 | B: 名稱 | C: 圖片 | ... | I: 操作 ││
│ └─────────────────────────────────────────────────┘│
└───────────────────────┬─────────────────────────────┘
┌─────────────────────────────────────────────────────┐
│ Apps Script │
│ ┌──────────────┐ ┌──────────────┐ ┌────────────┐ │
│ │ 程式碼.gs │ │ UpdateModal │ │ BrowseModal│ │
│ │ (後端邏輯) │ │ (側邊欄) │ │ (彈窗) │ │
│ └──────────────┘ └──────────────┘ └────────────┘ │
└───────────────────────┬─────────────────────────────┘
┌─────────────────────────────────────────────────────┐
│ Web App │
│ (獨立網址,不需開啟 Sheet) │
└─────────────────────────────────────────────────────┘

1.2 檔案結構#

檔案名稱類型用途
程式碼.gsScript後端邏輯、API、觸發器
UpdateModal.htmlHTML側邊欄編輯介面
BrowseModal.htmlHTML資料總覽彈窗
WebApp.htmlHTML獨立 Web App 介面

二、基礎概念#

2.1 Apps Script 與 Sheets 的關係#

Apps Script 可以「綁定」在特定的 Google 文件上,這種稱為 Container-bound Script

// 在綁定的 Script 中,可以直接取得試算表
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sheet = ss.getActiveSheet();
// 讀取資料
const value = sheet.getRange('A1').getValue();
// 寫入資料
sheet.getRange('A2').setValue('Hello World');

2.2 兩種觸發器(Trigger)#

類型執行身份權限需求使用場景
Simple Trigger使用者本人受限(無法存取需授權的服務)onOpen, onEdit
Installable Trigger安裝者(管理員)完整權限需要執行敏感操作

Simple Trigger 範例#

// 自動執行,但權限受限
function onOpen() {
SpreadsheetApp.getUi()
.createMenu('我的選單')
.addItem('功能一', 'myFunction')
.addToUi();
}

Installable Trigger 範例#

// 需手動安裝,但有完整權限
function installTrigger() {
ScriptApp.newTrigger('onEditTrigger')
.forSpreadsheet(SpreadsheetApp.getActive())
.onEdit()
.create();
}
function onEditTrigger(e) {
// 這裡可以執行需要權限的操作
// 例如:開啟側邊欄、修改受保護的儲存格
}

2.3 為什麼選擇 Installable Trigger?#

使用者在 H 欄選擇「📝 編輯」
觸發 Installable Trigger
用「安裝者」的權限執行
即使分頁有保護也能修改資料!

重點:Installable Trigger 讓一般使用者可以透過預設的操作流程來修改資料,而不需要直接的編輯權限。


三、核心功能實作#

3.1 選單與觸發器設定#

const EDIT_COL = 8; // H 欄
function onOpen() {
SpreadsheetApp.getUi()
.createMenu('更新管理')
.addItem('🔑 啟用功能(首次使用)', 'firstTimeAuth')
.addSeparator()
.addItem('➕ 新增資料', 'openBlankSidebar')
.addItem('📋 查看當前分頁資料', 'openBrowseModal')
.addSeparator()
.addSubMenu(SpreadsheetApp.getUi().createMenu('🔧 管理員功能')
.addItem('⚙️ 安裝觸發器', 'installTrigger'))
.addToUi();
}
function installTrigger() {
// 先移除舊的,避免重複
const triggers = ScriptApp.getProjectTriggers();
triggers.forEach(function(trigger) {
if (trigger.getHandlerFunction() === 'onEditTrigger') {
ScriptApp.deleteTrigger(trigger);
}
});
// 安裝新的
ScriptApp.newTrigger('onEditTrigger')
.forSpreadsheet(SpreadsheetApp.getActive())
.onEdit()
.create();
SpreadsheetApp.getActiveSpreadsheet().toast("觸發器安裝完成!", "✅", 3);
}

3.2 下拉選單觸發編輯/刪除#

function onEditTrigger(e) {
const range = e.range;
const sheet = range.getSheet();
const sheetName = sheet.getName();
// 檢查是否為 H 欄且非標題列
if (range.getColumn() === EDIT_COL && range.getRow() > 1) {
const currentRow = range.getRow();
const value = e.value;
// 檢查 A 欄有沒有資料
const id = sheet.getRange(currentRow, 1).getValue();
if (!id) {
range.setValue('-');
return;
}
// 📝 編輯
if (value === '📝 編輯') {
const rowValues = sheet.getRange(currentRow, 1, 1, 7).getValues()[0];
const productData = {
sheetName: sheetName,
id: rowValues[0],
name: rowValues[1],
image: rowValues[2],
description: rowValues[3],
price: rowValues[4],
note: rowValues[5],
date: rowValues[6],
rowNumber: currentRow
};
showSidebar(productData);
range.setValue('-');
}
// 🗑️ 刪除
if (value === '🗑️ 刪除') {
const ui = SpreadsheetApp.getUi();
const response = ui.alert(
'⚠️ 確認刪除',
'確定要刪除這筆資料嗎?',
ui.ButtonSet.YES_NO
);
if (response === ui.Button.YES) {
sheet.deleteRow(currentRow);
} else {
range.setValue('-');
}
}
}
}

3.3 側邊欄與 Modal#

// 開啟側邊欄
function showSidebar(data) {
const template = HtmlService.createTemplateFromFile('UpdateModal');
template.initialData = data ? JSON.stringify(data) : 'null';
const html = template.evaluate()
.setTitle('商品資料編輯')
.setSandboxMode(HtmlService.SandboxMode.IFRAME);
SpreadsheetApp.getUi().showSidebar(html);
}
// 開啟 Modal
function openBrowseModal() {
const template = HtmlService.createTemplateFromFile('BrowseModal');
const sheetName = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet().getName();
template.data = getAllProducts(sheetName);
template.sheetName = sheetName;
const html = template.evaluate()
.setWidth(750)
.setHeight(550);
SpreadsheetApp.getUi().showModalDialog(html, '📋 資料總覽');
}

3.4 HTML 模板傳值#

在 HTML 中使用 <?!= ?> 語法接收後端資料:

<script>
// 從後端接收資料
const initialData = <?!= initialData ?>;
const sheetName = '<?!= sheetName ?>';
// Vue 3 使用範例
const { createApp, ref, onMounted } = Vue;
createApp({
setup() {
const form = ref({});
onMounted(function() {
if (initialData) {
form.value = initialData;
}
});
return { form };
}
}).mount('#app');
</script>

四、權限與授權設計#

4.1 授權流程#

新用戶首次使用
點選任何選單功能
Google 彈出授權視窗
用戶勾選同意權限
完成授權,可使用所有功能

4.2 常見授權問題#

問題原因解決方式
功能無法使用未完成授權點選「首次授權」功能
授權後仍無法用漏勾權限去 Google 帳戶撤銷後重新授權
Modal 編輯按鈕失效該用戶未授權提示用戶先完成授權

4.3 授權引導頁面#

function showResetAuthInstructions() {
const html = HtmlService.createHtmlOutput(`
<h3>🔄 重置授權步驟</h3>
<ol>
<li>前往 <a href="https://myaccount.google.com/permissions" target="_blank">Google 權限設定</a></li>
<li>找到此試算表名稱</li>
<li>點擊「移除存取權」</li>
<li>回到試算表按 F5 重新整理</li>
<li>重新執行「首次授權」</li>
</ol>
`)
.setWidth(400)
.setHeight(300);
SpreadsheetApp.getUi().showModalDialog(html, '授權說明');
}

五、進階:Web App 部署#

5.1 什麼是 Web App?#

項目綁定在 SheetWeb App
網址有獨立網址
開啟方式從 Sheet 選單直接開網址
看到 Sheet?看得到看不到
程式碼有權限的人看得到完全隱藏
適合內部團隊給外部人用

5.2 費用說明#

完全免費! 🎉

項目費用限制
Apps Script免費每日執行時間 6 小時
Web App 部署免費無流量限制
網址免費Google 提供的子網域
SSL 憑證免費自動 HTTPS

5.3 Web App 入口函數#

function doGet(e) {
const template = HtmlService.createTemplateFromFile('WebApp');
// 取得所有分頁名稱
const ss = getSpreadsheet();
const sheets = ss.getSheets();
const sheetNames = sheets.map(function(s) { return s.getName(); });
template.sheetNames = JSON.stringify(sheetNames);
return template.evaluate()
.setTitle('商品資料管理系統')
.addMetaTag('viewport', 'width=device-width, initial-scale=1')
.setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL);
}

5.4 ⚠️ 關鍵注意事項:SPREADSHEET_ID#

這是最常見的錯誤來源!

問題:在 Web App 環境中,SpreadsheetApp.getActiveSpreadsheet() 會返回 null

原因:Web App 是獨立運行的,沒有「當前開啟的試算表」概念。

解決方案

// ❌ 錯誤寫法
const SPREADSHEET_ID = SpreadsheetApp.getActiveSpreadsheet().getId();
// ✅ 正確寫法:硬編碼試算表 ID
const SPREADSHEET_ID = 'YOUR_SPREADSHEET_ID_HERE';
// 取得試算表的通用函數
function getSpreadsheet() {
try {
// 先嘗試取得綁定的試算表(在 Sheet 內執行時)
const ss = SpreadsheetApp.getActiveSpreadsheet();
if (ss) return ss;
} catch (e) {}
// Web App 環境用 ID 開啟
return SpreadsheetApp.openById(SPREADSHEET_ID);
}

如何取得 ID?

從試算表網址:

https://docs.google.com/spreadsheets/d/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/edit#gid=0
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
這一段就是 ID(約 44 個字元)

5.5 部署步驟#

  1. 開啟 Apps Script 編輯器

  2. 點選「部署」→「新增部署作業」

  3. 設定部署選項

設定項目選項說明
類型網頁應用程式-
執行身分用你的權限執行(推薦)
誰可以存取任何人依需求選擇
  1. 點「部署」取得網址

5.6 ⚠️ 更新部署的注意事項#

每次修改程式碼後:

  1. 部署 → 管理部署作業
  2. 點右上角 鉛筆圖示(編輯)
  3. 版本必須選「新版本」
  4. 點「部署」
⚠️ 如果選擇舊版本號,修改不會生效!

5.7 API 設計建議#

為 Web App 設計專用的 API 函數:

// API: 取得資料
function getSheetData(sheetName) {
const emptyResult = { data: [], headers: [], total: 0 };
try {
const ss = getSpreadsheet();
const sheet = ss.getSheetByName(sheetName);
if (!sheet) return emptyResult;
const lastRow = sheet.getLastRow();
if (lastRow <= 1) return emptyResult;
const data = sheet.getRange(2, 1, lastRow - 1, 7).getValues();
const result = data.map(function(row, index) {
return {
rowNum: index + 2,
id: row[0],
name: row[1],
// ...
};
});
return { data: result, total: result.length };
} catch (e) {
console.log('錯誤:' + e.message);
return emptyResult;
}
}
// API: 儲存資料
function saveDataFromWeb(formData) {
const ss = getSpreadsheet();
const sheet = ss.getSheetByName(formData.sheetName);
// ... 儲存邏輯
return { success: true, message: "儲存成功" };
}
// API: 刪除資料
function deleteDataFromWeb(sheetName, rowNum) {
const ss = getSpreadsheet();
const sheet = ss.getSheetByName(sheetName);
sheet.deleteRow(rowNum);
return { success: true, message: "刪除成功" };
}

六、前端呼叫 Apps Script#

6.1 基本語法#

// 呼叫後端函數
google.script.run
.withSuccessHandler(function(result) {
console.log('成功:', result);
})
.withFailureHandler(function(error) {
console.log('失敗:', error);
})
.yourFunctionName(arg1, arg2);

6.2 完整範例#

function loadData() {
isLoading.value = true;
google.script.run
.withSuccessHandler(function(result) {
if (result && result.data) {
items.value = result.data;
} else {
items.value = [];
}
isLoading.value = false;
})
.withFailureHandler(function(err) {
showToast('載入失敗:' + err, 'error');
items.value = [];
isLoading.value = false;
})
.getSheetData(currentSheet.value);
}
function saveForm() {
if (!form.value.id) return;
isSaving.value = true;
const payload = { ...form.value, sheetName: currentSheet.value };
google.script.run
.withSuccessHandler(function(result) {
isSaving.value = false;
if (result.success) {
showToast(result.message, 'success');
loadData(); // 重新載入
}
})
.withFailureHandler(function(err) {
isSaving.value = false;
showToast('儲存失敗', 'error');
})
.saveDataFromWeb(payload);
}

七、部署權限深入解析(進階必讀)#

這是許多開發者會踩到的坑,尤其是公司帳號(Google Workspace)與一般 Google 帳號的行為差異

7.1 部署設定的兩個關鍵選項#

設定項目選項影響
執行身分我 (Me)用開發者權限執行,使用者不需要 Sheet 權限
存取應用程式的使用者用使用者自己的權限,需要給 Sheet 權限
誰可以存取僅限自己只有你能用
任何人不需登入就能用
任何擁有 Google 帳戶的人需要登入 Google 才能用

7.2 ⚠️ 常見問題:抓不到使用者 Email#

症狀Session.getActiveUser().getEmail() 回傳空字串

原因:部署設定為「任何人 (Anyone)」時,Google 為了隱私不會傳遞訪客的 Email。

function doGet(e) {
const userEmail = Session.getActiveUser().getEmail();
console.log(userEmail); // 輸出:""(空字串)
}

解決方案

將「誰可以存取」改為 「任何擁有 Google 帳戶的人」

部署 → 管理部署作業 → 編輯
誰可以存取:
❌ 任何人 (Anyone) → 抓不到 Email
✅ 任何擁有 Google 帳戶的人 → 可以抓到 Email
版本:選擇「新版本」
部署

設定後的行為變化

使用者開啟 Web App 網址
Google 先攔截,要求登入
登入成功後才執行 doGet
Session.getActiveUser().getEmail() 可正常取得 Email

7.3 ⚠️ 執行身分的權限陷阱#

情境比喻#

「執行身分:我」的運作方式:
使用者:「幫我修改這筆資料」
Web App(代理人)拿著「你的識別證」進入 Sheet
Google Sheet 記錄:「開發者 修改了資料」

兩種設定的比較#

執行身分Sheet 權限需求版本紀錄顯示安全性
我 (Me)使用者不需要權限只顯示開發者✅ 安全
使用者使用者需要編輯權限顯示實際操作者❌ 危險

為什麼不建議「執行身分:使用者」?#

❌ 問題:
1. 必須把 Sheet 開放「編輯權限」給每位使用者
2. 使用者可以繞過 Web App,直接開 Sheet 亂改
3. 資料安全性歸零

7.4 ✅ 最佳實踐:自己記錄修改人#

既然系統紀錄無法區分,就在資料中加入「修改人」欄位:

修改資料結構#

原本:A ~ G 欄(資料)+ H 欄(操作選單)
修改後:A ~ G 欄(資料)+ H 欄(修改人 Email)+ I 欄(操作選單)
// 操作欄從第 8 欄移到第 9 欄
const EDIT_COL = 9;

修改儲存函數#

function saveDataFromWeb(formData) {
const ss = getSpreadsheet();
const sheet = ss.getSheetByName(formData.sheetName);
// 取得當前使用者 Email
const currentUserEmail = Session.getActiveUser().getEmail();
// 資料陣列(1~8 欄)
const rowData = [
formData.id,
formData.name,
formData.image,
formData.description,
formData.price,
formData.note,
formData.date,
currentUserEmail // H 欄:修改人
];
// ... 儲存邏輯(第 9 欄是操作選單)
}

效果#

idnamedate修改人操作
001商品A2025-12-15[email protected]
002商品B2025-12-15[email protected]

7.5 公司帳號 vs 個人帳號差異#

Google Workspace(公司帳號)有額外的安全限制:

項目個人帳號公司帳號 (Workspace)
外部 App 存取通常允許可能被管理員限制
第三方授權自由可能需要管理員核准
跨網域分享自由可能被限制

常見錯誤訊息#

「這個應用程式遭到封鎖」
「您的機構不允許存取這個應用程式」

解決方式#

  1. 聯繫公司 IT 管理員開放權限
  2. 或將 Apps Script 專案發布為「內部應用程式」

7.6 推薦的部署設定組合#

內部團隊使用(推薦)#

執行身分:我 (Me)
誰可以存取:任何擁有 Google 帳戶的人
  • ✅ 使用者不需要 Sheet 權限
  • ✅ 可以取得使用者 Email
  • ✅ 資料安全性高

完全公開(表單類)#

執行身分:我 (Me)
誰可以存取:任何人
  • ✅ 訪客不需登入
  • ⚠️ 無法追蹤是誰提交的
  • ⚠️ 可能被濫用

高安全性需求#

執行身分:我 (Me)
誰可以存取:任何擁有 Google 帳戶的人
+ 白名單驗證 + 管理員分層
// ========================================
// 設定區
// ========================================
// 一般使用者白名單(留空 [] = 公開模式,允許所有 Google 帳戶)
const ALLOWED_USERS = [
// 留空代表允許所有人
];
// 管理員白名單(可看到進階功能)
const ADMIN_USERS = [
];
// ========================================
// 統一的權限檢查函數
// ========================================
function getUserInfo() {
const email = Session.getActiveUser().getEmail();
const lowerEmail = email.toLowerCase();
// 公開模式:白名單為空時,允許所有 Google 帳戶
const isPublic = ALLOWED_USERS.length === 0;
return {
email: email,
// 允許進入:公開模式 OR 在白名單內
isAllowed: isPublic || ALLOWED_USERS.some(u => u.toLowerCase() === lowerEmail),
// 管理員:必須在管理員名單內
isAdmin: ADMIN_USERS.some(u => u.toLowerCase() === lowerEmail)
};
}
// ========================================
// doGet 入口的權限檢查
// ========================================
function doGet(e) {
const userInfo = getUserInfo();
// 1. 檢查是否能取得 Email
if (!userInfo.email) {
return HtmlService.createHtmlOutput(`
<h2>⚠️ 無法識別您的身分</h2>
<p>請確認部署設定為「任何擁有 Google 帳戶的人」</p>
`);
}
// 2. 權限檢查
if (!userInfo.isAllowed) {
return HtmlService.createHtmlOutput(`
<h2>🚫 存取被拒</h2>
<p>您的帳號 (${userInfo.email}) 沒有權限。</p>
`);
}
// 3. 正常載入,傳遞使用者資訊給前端
const template = HtmlService.createTemplateFromFile('WebApp');
template.currentUser = JSON.stringify(userInfo);
return template.evaluate();
}

前端可根據 isAdmin 顯示/隱藏管理功能:

// 在 WebApp.html 中
const currentUser = <?!= currentUser ?>;
// 根據權限顯示按鈕
if (currentUser.isAdmin) {
// 顯示管理員專用按鈕
}

八、常見問題與解決方案#

8.1 問題排查清單#

問題可能原因解決方式
Web App 載入失敗SPREADSHEET_ID 未設定硬編碼正確的 ID
修改沒生效未選「新版本」部署重新部署為新版本
權限錯誤用戶未授權引導用戶完成授權
觸發器不運作未安裝或重複安裝檢查並重新安裝
Modal 編輯失敗呼叫者無權限改用觸發器方式
Email 抓不到部署設定為「任何人」改為「任何擁有 Google 帳戶的人」
公司帳號被擋Workspace 安全限制聯繫 IT 管理員
版本紀錄只顯示開發者執行身分設為「我」自己記錄修改人欄位

8.2 Debug 技巧#

// 在後端加入 log
function getSheetData(sheetName) {
console.log('開始取得資料,分頁:' + sheetName);
const ss = getSpreadsheet();
console.log('試算表:' + (ss ? ss.getName() : 'null'));
// ...
}
// 在 Apps Script 編輯器執行測試
function testGetSheetData() {
const result = getSheetData('Sheet1');
console.log('結果:' + JSON.stringify(result));
}

8.3 效能優化建議#

// ❌ 效能差:逐格讀取
for (let i = 2; i <= lastRow; i++) {
const value = sheet.getRange(i, 1).getValue();
}
// ✅ 效能好:批次讀取
const values = sheet.getRange(2, 1, lastRow - 1, 7).getValues();
values.forEach(function(row) {
// 處理資料
});

8.4 ⚠️ 重要:併發寫入的鎖定機制(LockService)#

當多人同時操作時,可能發生資料覆蓋重複寫入的問題。使用 LockService 可以確保同一時間只有一個人能寫入。

function saveDataFromWeb(formData) {
// 1. 取得鎖定
const lock = LockService.getScriptLock();
try {
// 等待取得鎖定(最多等 10 秒)
lock.waitLock(10000);
} catch (e) {
// 等不到鎖定,代表有其他人正在寫入
return { success: false, message: "系統忙碌中,請稍後再試" };
}
try {
// 2. 執行寫入操作
const ss = getSpreadsheet();
const sheet = ss.getSheetByName(formData.sheetName);
// ... 寫入邏輯 ...
return { success: true, message: "儲存成功" };
} catch (e) {
return { success: false, message: "錯誤:" + e.message };
} finally {
// 3. 一定要釋放鎖定!
lock.releaseLock();
}
}

LockService 的三種類型#

類型範圍使用場景
getScriptLock()整個 Script最常用,防止任何人同時執行
getUserLock()單一使用者防止同一人重複點擊
getDocumentLock()單一文件綁定特定 Sheet 的操作

流程示意#

使用者 A 開始儲存
取得 Lock ✅
執行寫入中...
│ ← 使用者 B 也要儲存
│ ↓
│ 等待 Lock... ⏳
│ │
寫入完成 │
↓ │
釋放 Lock │
取得 Lock ✅
執行寫入

最佳實踐#

// ⚠️ 一定要用 try-finally 確保釋放鎖定
const lock = LockService.getScriptLock();
try {
lock.waitLock(10000);
// 寫入操作
} finally {
lock.releaseLock(); // 無論成功失敗都要釋放!
}

九、完整程式碼結構#

9.1 檔案結構#

📁 Apps Script 專案
├── 程式碼.gs # 後端邏輯
│ ├── 設定區
│ │ ├── EDIT_COL = 9
│ │ ├── SPREADSHEET_ID
│ │ ├── ALLOWED_USERS[]
│ │ └── ADMIN_USERS[]
│ ├── 工具函數
│ │ ├── getUserInfo()
│ │ └── getSpreadsheet()
│ ├── Web App
│ │ └── doGet()
│ ├── API
│ │ ├── getSheetNames()
│ │ ├── getSheetData()
│ │ ├── saveDataFromWeb() # 含 LockService
│ │ └── deleteDataFromWeb()
│ ├── Sheet 觸發器
│ │ ├── onEditTrigger()
│ │ ├── showSidebar()
│ │ └── installTrigger()
│ └── 選單與初始化
│ ├── onOpen()
│ ├── initEditColumn()
│ └── initAllSheetsEditColumn()
├── UpdateModal.html # 側邊欄編輯介面
├── BrowseModal.html # 資料總覽彈窗
└── WebApp.html # 獨立 Web App

9.2 資料欄位對照#

欄位位置欄位名稱說明
A1id編號(主鍵)
B2name名稱
C3image圖片連結
D4description描述
E5price價格
F6note備註
G7date日期時間
H8email修改人 Email(自動記錄)
I9操作下拉選單(-/編輯/刪除)

9.3 設定區範例#

// ========================================
// 設定區(根據需求修改)
// ========================================
// 操作欄位置(第 8 欄存 Email,所以操作欄在第 9 欄)
const EDIT_COL = 9;
// 試算表 ID(從網址取得)
const SPREADSHEET_ID = '你的試算表ID';
// 一般使用者白名單(空陣列 = 公開模式)
const ALLOWED_USERS = [
];
// 管理員白名單
const ADMIN_USERS = [
];

結語#

Google Apps Script 雖然有其限制,但對於快速建立內部工具來說是非常好的選擇:

優點#

  • ✅ 完全免費
  • ✅ 不需要另外架設伺服器
  • ✅ 與 Google 生態系無縫整合
  • ✅ 部署簡單,一鍵上線

限制#

  • ⚠️ 每日執行時間限制(6 小時)
  • ⚠️ 程式碼對編輯者可見(除非用 Web App)
  • ⚠️ 效能不如專業後端

適用場景#

  • 內部資料管理系統
  • 表單提交後處理
  • 自動化報表生成
  • 快速原型開發

希望這份指南能幫助你快速上手 Google Apps Script 開發!


Google Apps Script × Sheets 實戰指南:從側邊欄到 Web App 部署
https://laplusda.com/posts/google-apps-script-guide/
作者
Zero
發佈於
2025-12-15
許可協議
CC BY-NC-SA 4.0
這篇文章有幫助嗎?

回報錯字、失效連結,或告訴我你想看的延伸主題。