[實作筆記] 用 AI 寫一套自動開單系統
[實作筆記] 用 AI 寫一套自動開單系統
不想再手動打 Word 和記帳了!
分享如何用 Google 免費工具 + AI,打造整合收據與自動歸檔的行政系統。
以前開收據的流程是:打開 Word 範本 ➞ 填資料 ➞ 另存新檔 ➞ 打開 Excel ➞ 登記帳務。只要一忙起來,不是忘記存檔就是記錯帳。
所以我希望做一個系統,只要在手機網頁上填一次資料,後面所有事情自動完成。
這套系統不需要租伺服器,只需要你的 Google 雲端硬碟。請先建立這三個檔案,並把 ID 記下來。
XX 工作室 收據
日期:{{date}}
茲收到:{{name}} 先生/小姐
金額:新台幣 {{price_chinese}} (NT$ {{price}})
- Google Sheet: 建立新試算表,分頁名稱改為「收據紀錄」。
- Google Drive 資料夾: 建立一個空資料夾,用來存生成的 PDF。
這段是系統的大腦。請在 Google Sheet 點選「擴充功能」 > 「Apps Script」,將原本的內容清空,貼上這段代碼。
const CONFIG = {
TEMPLATE_ID: '請填入_你的DOC範本_ID',
FOLDER_ID: '請填入_資料夾_ID',
SHEET_NAME: '收據紀錄'
};
function doGet() {
return HtmlService.createHtmlOutputFromFile('index')
.setTitle('自動開單系統')
.setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL)
.addMetaTag('viewport', 'width=device-width, initial-scale=1');
}
// 核心處理函式
function processForm(data) {
const lock = LockService.getScriptLock();
if (!lock.tryLock(10000)) return { success: false, error: "系統忙碌中" };
try {
// 1. 準備資料
const docFile = DriveApp.getFileById(CONFIG.TEMPLATE_ID);
const folder = DriveApp.getFolderById(CONFIG.FOLDER_ID);
const dateStr = data.date.replace(/-/g, '/');
const priceInt = parseInt(data.price);
const chinesePrice = toChineseMoney(priceInt); // 轉國字大寫
// 2. 複製範本
const filename = `收據_${data.name}_${dateStr}`;
const newFile = docFile.makeCopy(filename, folder);
const doc = DocumentApp.openById(newFile.getId());
const body = doc.getBody();
// 3. 替換變數 (對應 Word 裡的 {{變數}})
body.replaceText("{{name}}", data.name);
body.replaceText("{{date}}", dateStr);
body.replaceText("{{item}}", data.item);
body.replaceText("{{price}}", data.price);
body.replaceText("{{price_chinese}}", chinesePrice);
doc.saveAndClose();
// 4. 寫入 Google Sheet
const ss = SpreadsheetApp.getActiveSpreadsheet();
let sheet = ss.getSheetByName(CONFIG.SHEET_NAME);
if (!sheet) sheet = ss.insertSheet(CONFIG.SHEET_NAME);
sheet.appendRow([
new Date(), // 建立時間
data.name, // 姓名
data.item, // 項目
priceInt, // 金額
newFile.getUrl() // 檔案連結
]);
return { success: true, url: newFile.getUrl() };
} catch (e) {
return { success: false, error: e.toString() };
} finally {
lock.releaseLock();
}
}
// 數字轉中文大寫工具
function toChineseMoney(n) {
if (isNaN(n)) return "";
const digit = ['零', '壹', '貳', '參', '肆', '伍', '陸', '柒', '捌', '玖'];
const unit = [['元', '萬', '億'], ['', '拾', '佰', '仟']];
let s = '';
n = Math.abs(n);
let integerPart = Math.floor(n);
for (let i = 0; i < unit[0].length && integerPart > 0; i++) {
let p = '';
for (let j = 0; j < unit[1].length && integerPart > 0; j++) {
p = digit[integerPart % 10] + unit[1][j] + p;
integerPart = Math.floor(integerPart / 10);
}
s = p.replace(/(零.)*零$/, '').replace(/^$/, '零') + unit[0][i] + s;
}
return s.replace(/(零.)*零元/, '元').replace(/(零.)+/g, '零').replace(/^整$/, '零元整') + "整";
}
在 Apps Script 左側新增一個 index.html 檔案。我加入了一點「玻璃擬態」風格,並預留了上方分頁籤的位置,讓系統看起來比較不呆板。
🧾 快速開立
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
body {
background: linear-gradient(135deg, #dbeafe, #eff6ff);
font-family: 'Noto Sans TC', sans-serif; padding: 20px;
min-height: 100vh; display: flex; justify-content: center;
}
.container { width: 100%; max-width: 450px; }
/* 玻璃擬態卡片 */
.glass-card {
background: rgba(255, 255, 255, 0.75);
backdrop-filter: blur(12px);
border: 1px solid rgba(255, 255, 255, 0.5);
border-radius: 20px; padding: 30px;
box-shadow: 0 10px 25px rgba(0,0,0,0.05);
}
input {
width: 100%; padding: 12px; margin-bottom: 15px;
border: 1px solid #fff; border-radius: 10px;
background: rgba(255,255,255,0.6); font-size: 16px;
box-sizing: border-box; transition: 0.3s;
}
input:focus { outline: none; border-color: #3b82f6; background: #fff; }
button {
width: 100%; padding: 14px; background: #2563eb; color: white;
border: none; border-radius: 10px; font-size: 1.1rem; font-weight: bold;
cursor: pointer; transition: transform 0.1s;
}
button:active { transform: scale(0.98); }
.status-msg { margin-top: 15px; text-align: center; font-size: 0.9rem; }
</style>
</head>
<body>
<div class="container">
<div class="glass-card">
<h2 style="text-align:center; color:#1e3a8a; margin-top:0;">🧾 收據開立</h2>
<form id="mainForm">
<label>姓名</label>
<input type="text" name="name" required placeholder="請輸入姓名">
<label>日期</label>
<input type="date" name="date" required>
<label>項目</label>
<input type="text" name="item" required placeholder="例如:服務費">
<label>金額</label>
<input type="number" name="price" required placeholder="例如:2000">
<button type="button" onclick="submitData(this)">確認開立</button>
</form>
<div id="status" class="status-msg"></div>
</div>
</div>
<script>
document.querySelector('input[type="date"]').valueAsDate = new Date();
function submitData(btn) {
btn.textContent = "處理中..."; btn.disabled = true;
const form = document.getElementById('mainForm');
google.script.run
.withSuccessHandler(res => {
btn.textContent = "確認開立"; btn.disabled = false;
if (res.success) {
document.getElementById('status').innerHTML =
`<span style="color:green">✅ 成功!<a href="${res.url}" target="_blank">下載文件</a></span>`;
form.reset();
document.querySelector('input[type="date"]').valueAsDate = new Date();
} else {
document.getElementById('status').innerHTML = `<span style="color:red">❌ 錯誤:${res.error}</span>`;
}
})
.processForm(Object.fromEntries(new FormData(form)));
}
</script>
</body>
</html>
上面的程式碼只是基礎版。如果你想要更完整的功能,不需要自己學寫程式!這裡提供我用來請 AI 修改的 Prompt (指令),你可以複製覺得好用的功能,直接去問 AI:
這套系統目前對我來說很好用,但它絕對不是完美的。我整理了一些這個系統的「亮點」與「可以改進的地方」,希望能給你更多靈感去修改出專屬於你的版本:
其實在做這個系統之前,我也想過:「直接買現成的 POS 系統不是比較快嗎?」
但現成的軟體,往往是「功能多到用不到」,或者「少了一個我最想要的關鍵功能」。自己用 AI 寫程式的好處,就是你可以100% 貼合自己的工作習慣。
寫程式最難的一步,往往是「不知道從何問起」。希望這篇筆記提供的程式碼骨架和 Prompt,能成為你的起跑點。
不用怕把程式改壞,因為有 AI 在,隨時都能修好它。試著動手做做看,那種「電腦幫我省下 1 小時」的成就感,真的很棒!
如果你改出了更有趣的功能,歡迎留言跟我分享,我也很想知道這套系統還能進化成什麼樣子!✨
留言
張貼留言