從 Google Sheet 資料中心,建立可分享的戰情室看板
本單元會帶你用 AI 協助產生 Apps Script 與 HTML Web App,將 Google Sheet 資料轉成可視覺化、可分享、可通知的管理看板。
一、本單元你會完成什麼?
本單元結束前,你會完成一個可以用網址開啟的「生產進度戰情室」,並能將連結寄送給主管或團隊成員查看。
使用 M3-M6 建立的 Google Sheet 資料中心,作為戰情室的資料來源。
負責讀取 Google Sheet、統計 KPI、整理延誤清單與今日追蹤項目。
負責呈現戰情室畫面,包括統計卡片、狀態標籤、清單與響應式版面。
部署後取得可開啟的戰情室網址,可分享、寄信或嵌入 Google Sites。
二、認識本單元要完成的戰情室
本單元不是單純製作 Google Sheet 圖表,而是把資料表轉成一個可以透過網址開啟的「部門共用戰情室看板」。
戰情室可以讓主管、生管、製造、品管、倉儲或其他相關單位快速查看目前狀態,例如總筆數、已完成、進行中、延誤、未產生檢查表,以及今日需要追蹤的項目。
生產進度戰情室
資料來源:Google Sheet|更新時間:今日 08:30| 製令編號 | 製程 | 負責人 | 預計完工日 | 狀態 |
|---|---|---|---|---|
| A511-1150630009 | 研磨 / 平面修整 | 製造一課 | 2026/07/11 | 延誤 |
| A511-1150630010 | 外發烤漆 | 生管 | 2026/07/12 | 待追蹤 |
三、開始前準備清單
| 準備項目 | 你需要完成什麼 | 完成確認 |
|---|---|---|
| Google Sheet 資料中心 | 已完成 M3-M6 的資料整理、產表狀態與通知狀態欄位設計。 | □ 已完成 |
| 資料表頁籤 | 頁籤名稱固定為「資料表」。 | □ 已完成 |
| 欄位順序 | 欄位順序與本講義一致,或你已知道如何調整程式中的欄位位置。 | □ 已完成 |
| 狀態欄位 | 狀態值固定,例如未開始、進行中、已完成、延誤。 | □ 已完成 |
| 產表狀態 | 固定為未產生、已產生、產生失敗。 | □ 已完成 |
| 測試資料 | 至少準備 5 筆資料,包含完成、進行中、延誤與未產生等狀態。 | □ 已完成 |
| Apps Script 權限 | 可以從 Google Sheet 開啟 Apps Script,並可部署 Web App。 | □ 已完成 |
| 測試信箱 | 準備一個可收信的測試信箱,用來接收戰情室連結。 | □ 已完成 |
四、操作總流程:請照這個順序完成
| 步驟 | 你要做的事 | 使用工具 | 完成標準 |
|---|---|---|---|
| Step 1 | 確認資料表欄位 | Google Sheet | 欄位完整且狀態一致。 |
| Step 2 | 準備測試資料 | Google Sheet | 至少有完成、進行中、延誤、未產生資料。 |
| Step 3 | 用 AI 產生 Code.gs | GPTs / Gemini | AI 產出後端程式。 |
| Step 4 | 用 AI 產生 Index.html | GPTs / Gemini | AI 產出前端畫面。 |
| Step 5 | 貼上 Code.gs | Apps Script | 程式已儲存。 |
| Step 6 | 新增 Index.html | Apps Script | HTML 檔案已建立。 |
| Step 7 | 測試資料讀取 | Apps Script | getDashboardData 可正常執行。 |
| Step 8 | 部署 Web App | Apps Script | 取得戰情室網址。 |
| Step 9 | 開啟網址檢查看板 | 瀏覽器 | KPI 與清單正常顯示。 |
| Step 10 | 寄送戰情室連結 | MailApp / Gmail | 測試信箱收到連結。 |
五、Google Sheet 欄位準備
戰情室要能正確顯示,前提是 Google Sheet 欄位穩定、順序清楚、狀態值一致。
| 欄位 | 欄位名稱 | 用途 | 範例 |
|---|---|---|---|
| A | 製令編號 | 戰情室追蹤主鍵。 | A511-1150630009 |
| B | 品名 | 顯示產品資訊。 | CB-二管直角立式吊架 |
| C | 規格 | 顯示產品規格。 | 410*211*669 |
| D | 預計產量 | 顯示數量。 | 100 |
| E | 加工順序 | 顯示製程順序。 | 0010 |
| F | 製程名稱 | 顯示目前製程。 | 手工焊接 |
| G | 狀態 | 統計完成、進行中、延誤。 | 未開始 / 進行中 / 已完成 / 延誤 |
| H | 負責人 | 顯示責任歸屬。 | 製造一課 |
| I | 通知信箱 | 後續寄信通知。 | user@company.com |
| J | 產表狀態 | 自主檢查表是否已產生。 | 已產生 / 未產生 |
| K | 預計完工日 | 判斷是否延誤。 | 2026/07/11 |
| L | 最後更新時間 | 顯示資料新鮮度。 | 2026/07/08 08:30 |
六、測試資料範例
如果你的資料表目前資料不足,可以先使用以下測試資料驗證戰情室是否可以正常顯示。
| 製令編號 | 品名 | 規格 | 預計產量 | 加工順序 | 製程名稱 | 狀態 | 負責人 | 通知信箱 | 產表狀態 | 預計完工日 |
|---|---|---|---|---|---|---|---|---|---|---|
| A511-1150630009 | CB-二管直角立式吊架 | 410*211*669 | 100 | 0010 | 手工焊接 | 延誤 | 製造一課 | test@example.com | 已產生 | 2026/07/11 |
| A511-1150630010 | CB-二管直角立式吊架 | 410*211*669 | 100 | 0020 | 固定前管 | 進行中 | 製造二課 | test@example.com | 未產生 | 2026/07/12 |
| A511-1150630011 | 展示架底座 | 300*200*150 | 50 | 0030 | 外發烤漆 | 已完成 | 生管 | test@example.com | 已產生 | 2026/07/10 |
| A511-1150630012 | 層板支架 | 500*100*80 | 80 | 0040 | 包裝 | 未開始 | 包裝課 | test@example.com | 未產生 | 2026/07/15 |
七、用 AI 產生戰情室程式碼
本單元不是要求你從零寫程式,而是學會用 AI 產生初版程式,並能看懂哪些地方要依照自己的資料表調整。
Prompt 1:請 AI 產生 Code.gs
請幫我產生 Google Apps Script 的 Code.gs。
目標:
把 Google Sheet「資料表」頁籤中的資料讀取出來,並提供給 HTML Web App 使用。
欄位順序如下:
A欄:製令編號
B欄:品名
C欄:規格
D欄:預計產量
E欄:加工順序
F欄:製程名稱
G欄:狀態
H欄:負責人
I欄:通知信箱
J欄:產表狀態
K欄:預計完工日
L欄:最後更新時間
請產生:
1. doGet(),用來顯示 Index.html
2. getDashboardData(),用來回傳以下資料:
- 總筆數
- 已完成數
- 進行中數
- 延誤數
- 未產生檢查表數
- 延誤清單
- 今日需追蹤清單
3. 請加上適合初學者閱讀的註解。
4. 請加入基本錯誤處理,例如找不到「資料表」時回傳錯誤訊息。
Prompt 2:請 AI 產生 Index.html
請幫我產生 Google Apps Script HTML Service 使用的 Index.html。
目標:
建立一個企業內部用的生產進度戰情室看板。
畫面需要包含:
1. 標題:生產進度戰情室
2. 最後更新時間
3. KPI 卡片:
- 總筆數
- 已完成
- 進行中
- 延誤中
- 未產表
4. 延誤製程清單
5. 今日需追蹤項目
6. 狀態標籤顏色:
- 延誤:紅色
- 進行中:黃色
- 已完成:綠色
- 未產生:紫色
7. 使用 google.script.run 呼叫 getDashboardData()
8. 響應式設計,手機與電腦都能查看。
9. 請加上初學者看得懂的註解。
八、打開 Apps Script 並貼上 Code.gs
操作步驟
- 打開你的 Google Sheet。
- 點選上方選單「擴充功能」。
- 選擇「Apps Script」。
- 將專案命名,例如「生產戰情室看板」。
- 打開 Code.gs。
- 刪除預設程式。
- 貼上 AI 產生的 Code.gs。
- 按下儲存。
- 確認程式中有
doGet()與getDashboardData()兩個函式。
Code.gs 範例
function doGet() {
return HtmlService
.createHtmlOutputFromFile('Index')
.setTitle('生產進度戰情室')
.setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL);
}
function getDashboardData() {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sheet = ss.getSheetByName('資料表');
if (!sheet) {
return {
error: true,
message: '找不到「資料表」頁籤,請確認頁籤名稱是否正確。'
};
}
const values = sheet.getDataRange().getValues();
const rows = values.slice(1);
const items = rows
.filter(row => row[0])
.map(row => {
return {
orderNo: row[0],
productName: row[1],
spec: row[2],
qty: row[3],
processSeq: row[4],
processName: row[5],
status: row[6],
owner: row[7],
email: row[8],
sheetStatus: row[9],
dueDate: row[10],
updatedAt: row[11]
};
});
const total = items.length;
const completed = items.filter(item => item.status === '已完成').length;
const inProgress = items.filter(item => item.status === '進行中').length;
const delayed = items.filter(item => item.status === '延誤').length;
const notGenerated = items.filter(item => item.sheetStatus === '未產生').length;
const delayedList = items.filter(item => item.status === '延誤');
const followUpList = items.filter(item =>
item.status === '延誤' ||
item.status === '進行中' ||
item.sheetStatus === '未產生'
);
return {
error: false,
total,
completed,
inProgress,
delayed,
notGenerated,
delayedList,
followUpList,
updatedAt: new Date().toLocaleString('zh-TW')
};
}
九、新增 Index.html 並貼上前端程式
操作步驟
- 在 Apps Script 左側點選「+」。
- 選擇「HTML」。
- 檔案命名為
Index。 - 刪除預設 HTML。
- 貼上 AI 產生的 Index.html。
- 按下儲存。
- 確認 Code.gs 中的
createHtmlOutputFromFile('Index')與 HTML 檔名一致。
Index.html 範例
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<style>
body {
margin: 0;
font-family: Arial, "Microsoft JhengHei", sans-serif;
background: #07152f;
color: #e5e7eb;
padding: 24px;
}
h1 {
margin: 0 0 6px;
font-size: 28px;
}
.sub {
color: #94a3b8;
margin-bottom: 24px;
}
.cards {
display: grid;
grid-template-columns: repeat(5, 1fr);
gap: 14px;
margin-bottom: 24px;
}
.card {
background: #111827;
border: 1px solid #334155;
border-radius: 16px;
padding: 18px;
}
.label {
color: #94a3b8;
font-size: 14px;
}
.value {
font-size: 32px;
font-weight: bold;
margin-top: 6px;
}
.blue { color: #38bdf8; }
.green { color: #22c55e; }
.yellow { color: #facc15; }
.red { color: #ef4444; }
.purple { color: #a855f7; }
table {
width: 100%;
border-collapse: collapse;
background: #020617;
border-radius: 16px;
overflow: hidden;
margin-top: 12px;
}
th, td {
border: 1px solid #334155;
padding: 10px 12px;
text-align: left;
}
th {
background: #1e293b;
color: #cbd5e1;
}
.badge {
padding: 4px 10px;
border-radius: 999px;
font-size: 12px;
font-weight: bold;
}
.badge-red {
background: rgba(239, 68, 68, .18);
color: #fecaca;
border: 1px solid rgba(239, 68, 68, .45);
}
.badge-yellow {
background: rgba(250, 204, 21, .16);
color: #fde68a;
border: 1px solid rgba(250, 204, 21, .45);
}
@media (max-width: 900px) {
.cards {
grid-template-columns: 1fr;
}
}
</style>
</head>
<body>
<h1>生產進度戰情室</h1>
<div class="sub" id="updatedAt">資料讀取中...</div>
<div class="cards">
<div class="card"><div class="label">總筆數</div><div class="value blue" id="total">-</div></div>
<div class="card"><div class="label">已完成</div><div class="value green" id="completed">-</div></div>
<div class="card"><div class="label">進行中</div><div class="value yellow" id="inProgress">-</div></div>
<div class="card"><div class="label">延誤中</div><div class="value red" id="delayed">-</div></div>
<div class="card"><div class="label">未產表</div><div class="value purple" id="notGenerated">-</div></div>
</div>
<h2>延誤製程清單</h2>
<table>
<thead>
<tr>
<th>製令編號</th>
<th>品名</th>
<th>製程</th>
<th>負責人</th>
<th>預計完工日</th>
<th>狀態</th>
</tr>
</thead>
<tbody id="delayedList"></tbody>
</table>
<h2>今日需追蹤項目</h2>
<table>
<thead>
<tr>
<th>製令編號</th>
<th>製程</th>
<th>負責人</th>
<th>產表狀態</th>
<th>狀態</th>
</tr>
</thead>
<tbody id="followUpList"></tbody>
</table>
<script>
google.script.run
.withSuccessHandler(renderDashboard)
.getDashboardData();
function renderDashboard(data) {
if (data.error) {
document.body.innerHTML = '<h1>資料讀取錯誤</h1><p>' + data.message + '</p>';
return;
}
document.getElementById('updatedAt').textContent = '最後更新時間:' + data.updatedAt;
document.getElementById('total').textContent = data.total;
document.getElementById('completed').textContent = data.completed;
document.getElementById('inProgress').textContent = data.inProgress;
document.getElementById('delayed').textContent = data.delayed;
document.getElementById('notGenerated').textContent = data.notGenerated;
renderDelayedList(data.delayedList);
renderFollowUpList(data.followUpList);
}
function renderDelayedList(list) {
const tbody = document.getElementById('delayedList');
tbody.innerHTML = '';
if (list.length === 0) {
tbody.innerHTML = '<tr><td colspan="6">目前沒有延誤項目。</td></tr>';
return;
}
list.forEach(item => {
tbody.innerHTML += `
<tr>
<td>${item.orderNo}</td>
<td>${item.productName}</td>
<td>${item.processName}</td>
<td>${item.owner}</td>
<td>${item.dueDate}</td>
<td><span class="badge badge-red">${item.status}</span></td>
</tr>
`;
});
}
function renderFollowUpList(list) {
const tbody = document.getElementById('followUpList');
tbody.innerHTML = '';
if (list.length === 0) {
tbody.innerHTML = '<tr><td colspan="5">目前沒有待追蹤項目。</td></tr>';
return;
}
list.forEach(item => {
tbody.innerHTML += `
<tr>
<td>${item.orderNo}</td>
<td>${item.processName}</td>
<td>${item.owner}</td>
<td>${item.sheetStatus}</td>
<td><span class="badge badge-yellow">${item.status}</span></td>
</tr>
`;
});
}
</script>
</body>
</html>
十、程式碼閱讀指南
| 程式片段 | 白話意思 | 你可能需要調整哪裡 |
|---|---|---|
getSheetByName('資料表') |
讀取資料表頁籤。 | 如果頁籤名稱不同,要改。 |
values.slice(1) |
跳過第 1 列欄位名稱。 | 如果資料不是從第 2 列開始,要調整。 |
row[0] |
讀取 A 欄製令編號。 | 如果欄位順序不同,要調整。 |
item.status === '已完成' |
統計已完成筆數。 | 狀態文字要完全一致。 |
item.sheetStatus === '未產生' |
統計未產生檢查表。 | 產表狀態文字要一致。 |
google.script.run |
前端呼叫後端資料。 | 通常不用改。 |
十一、第一次測試資料讀取
操作步驟
- 在 Apps Script 上方函式下拉選單選擇
getDashboardData。 - 按下「執行」。
- 第一次執行會要求授權。
- 依照畫面完成 Google 帳號授權。
- 查看執行紀錄是否有紅色錯誤訊息。
- 若沒有錯誤,代表後端可讀取資料。
getDashboardData() 不出現紅色錯誤訊息,就可以進入 Web App 部署。
十二、部署成 Web App
操作步驟
- 點 Apps Script 右上角「部署」。
- 選擇「新增部署作業」。
- 部署類型選「網頁應用程式」。
- 說明填入「M7 生產戰情室初版」。
- 執行身分選「我」。
- 存取權限依公司政策選擇「公司內部使用者」或「知道連結的人」。
- 按下部署。
- 依提示完成授權。
- 複製 Web App URL。
- 用瀏覽器開啟網址測試。
十三、修改程式後如何重新部署
如果你修改了 Code.gs 或 Index.html,原本的 Web App 不一定會立即更新。請依照以下步驟重新部署。
重新部署步驟
- 修改程式後先按儲存。
- 點選右上角「部署」。
- 選擇「管理部署作業」。
- 找到原本的 Web App。
- 點選編輯。
- 版本選擇「新增版本」。
- 按下部署。
- 重新打開 Web App URL 測試。
十四、打開戰情室後要檢查什麼?
| 檢查項目 | 你要確認什麼 | 如果不正確怎麼辦 |
|---|---|---|
| 看板是否能開啟 | Web App URL 是否正常顯示畫面。 | 檢查部署權限。 |
| KPI 是否有數字 | 總筆數、已完成、進行中、延誤、未產表是否顯示。 | 檢查資料表是否有資料。 |
| 統計是否正確 | 數字是否與 Sheet 狀態一致。 | 檢查狀態文字是否一致。 |
| 延誤清單是否顯示 | 狀態為延誤的資料是否列出。 | 檢查 G 欄狀態。 |
| 今日追蹤項目是否顯示 | 進行中、延誤、未產生是否列出。 | 檢查篩選條件。 |
| 權限是否正確 | 其他人是否能打開網址。 | 調整 Web App 存取設定。 |
十五、自動寄送戰情室連結
當戰情室建立完成後,可以把 Web App 連結用 MailApp 寄送給主管或相關部門。測試時請先寄給自己的信箱。
操作步驟
- 確認 Web App URL 可以打開。
- 回到 Apps Script。
- 新增
sendDashboardLink()函式。 - 將收件人改成自己的測試信箱。
- 將
dashboardUrl改成你的 Web App URL。 - 儲存。
- 執行
sendDashboardLink()。 - 檢查 Gmail 是否收到信。
- 點信中的連結,確認可開啟戰情室。
function sendDashboardLink() {
const recipient = '請改成你的測試信箱';
const dashboardUrl = '請貼上你的 Web App URL';
const subject = '【今日生產戰情室】請確認延誤與待追蹤項目';
const body =
'您好:\n\n' +
'今日生產戰情室已更新,請查看以下項目:\n' +
'1. 延誤製程清單\n' +
'2. 未產生自主檢查表項目\n' +
'3. 今日需追蹤製令\n' +
'4. 需要主管協調的項目\n\n' +
'戰情室連結:\n' +
dashboardUrl + '\n\n' +
'此信件由 Apps Script 自動寄出。';
MailApp.sendEmail(recipient, subject, body);
}
十六、將戰情室嵌入 Google Sites
若公司希望建立一個跨部門查詢入口,可以把 Web App 放進 Google Sites,讓戰情室成為內部管理入口的一部分。
操作步驟
- 開啟 Google Sites。
- 新增一個頁面,命名為「生產戰情室」。
- 點選「插入」。
- 選擇「嵌入」。
- 貼上 Apps Script Web App URL。
- 調整高度與寬度。
- 發布網站。
十七、用 AI 優化戰情室
完成初版後,你可以用 AI 逐步優化戰情室。AI 協作不是一次完成,而是持續改善。
| 優化方向 | 可以請 AI 做什麼 |
|---|---|
| 增加篩選 | 依負責人、製程、狀態篩選。 |
| 增加搜尋 | 可輸入製令編號查詢。 |
| 增加顏色 | 延誤紅色、進行中黃色、已完成綠色。 |
| 增加統計 | 依負責人統計延誤數。 |
| 增加排序 | 延誤項目依預計完工日排序。 |
| 增加錯誤提示 | 若讀不到資料,畫面顯示原因。 |
請幫我優化這個 Google Apps Script Web App 戰情室。
我希望增加:
1. 依負責人篩選
2. 依狀態篩選
3. 製令編號搜尋
4. 延誤項目依預計完工日排序
5. 若資料讀取失敗,畫面要顯示錯誤提示
請分別提供需要修改的 Code.gs 與 Index.html。
十八、學員練習:設計自己的戰情室
練習任務
- 選擇一個高耗時任務。
- 設計 Google Sheet 欄位。
- 定義 KPI 指標。
- 定義要顯示的清單。
- 定義誰需要看這個戰情室。
- 定義是否要寄送連結。
- 完成下方表格。
| 我的高耗時任務 | 資料來源 | Sheet 欄位 | 戰情室要顯示什麼 | 誰需要收到連結 |
|---|---|---|---|---|
| 例:外發烤漆進度追蹤 | 外發紀錄 / 回廠回報 | 製令、廠商、送出日、預計回廠日、狀態 | 逾期未回、今日待追蹤、外發廠商統計 | 生管、倉儲、主管 |
十九、常見錯誤與排除方式
| 問題 | 可能原因 | 處理方式 |
|---|---|---|
| 戰情室打開是空白 | Index.html 名稱錯誤,或 doGet 指向的檔名不一致。 | 確認檔案名稱是 Index,且 Code.gs 中為 createHtmlOutputFromFile('Index')。 |
| 找不到資料表 | Google Sheet 頁籤名稱不是「資料表」。 | 將 Sheet 頁籤改名為「資料表」,或修改程式中的 getSheetByName。 |
| KPI 都是 0 | 狀態欄位文字不一致。 | 統一狀態文字,例如固定使用「已完成」。 |
| 日期顯示怪怪的 | Google Sheet 日期格式不同。 | 將日期轉文字或統一格式。 |
| 部署後別人看不到 | Web App 存取權限設定過嚴。 | 確認「誰可以存取」是否符合使用情境。 |
| 修改後畫面沒變 | 沒有重新部署新版。 | 到「管理部署作業」新增版本並重新部署。 |
| 寄信失敗 | 尚未授權 MailApp,或收件信箱格式錯誤。 | 先手動執行一次寄信函式,完成 Google 授權。 |
| AI 產生的程式不能跑 | 欄位名稱與順序不一致。 | 回到 Prompt 補上正確欄位,請 AI 重新調整。 |
二十、學員完成檢核表
| 檢核項目 | 完成標準 | 是否完成 |
|---|---|---|
| 資料表完成 | 有「資料表」頁籤且欄位完整。 | □ 是 □ 否 |
| 狀態欄位一致 | 狀態文字固定,無混用。 | □ 是 □ 否 |
| Code.gs 完成 | 已貼上並儲存。 | □ 是 □ 否 |
| Index.html 完成 | 已新增 Index 並貼上 HTML。 | □ 是 □ 否 |
| 後端測試完成 | getDashboardData() 可執行。 | □ 是 □ 否 |
| Web App 部署完成 | 已取得 Web App URL。 | □ 是 □ 否 |
| 看板顯示完成 | KPI 與清單正常顯示。 | □ 是 □ 否 |
| 權限測試完成 | 目標使用者可開啟連結。 | □ 是 □ 否 |
| 通知信測試完成 | 測試信箱收到戰情室連結。 | □ 是 □ 否 |
| 錯誤排除能力 | 知道空白、權限、統計錯誤要查哪裡。 | □ 是 □ 否 |
二十一、本單元重點整理
戰情室讀的是穩定欄位資料,而不是漂亮但結構不穩的表格。
負責讀資料、統計資料、整理清單,並把資料交給網頁畫面。
將資料轉成 KPI 卡片、狀態清單與可分享的網頁看板。
AI 可以協助產生初版程式、修正錯誤、優化畫面,但資料結構仍要由你定義清楚。
講師專業背景
Shirley 具備多年企業系統、流程優化與管理顧問實務經驗,並持有多項人才發展與學習設計相關認證,包括:
- ATD 變革管理認證
- ATD 諮詢技巧認證
- ATD 人員績效改善認證
- ATD 微學習認證
- ATD 學習效果評估認證
- iTE 學習移轉設計師認證
本課程設計結合實務流程改善、AI 工具應用、學習移轉與績效改善觀點,協助學員把 AI 從單次問答轉化為可落地的工作流。