0. 作品介紹
封面
1. AI 提示詞
把這段指令貼給 AI,讓它幫你生成程式碼。
我想要建立一個 【產品造型設計系統】
幫我用Google 試算表建立 【無人機造型資料庫】
我希望有些資料我可以直接在試算表更改首頁可以直接呈現
需求說明 【現有產品照片、造型風格、需要有拉桿調整造型】
要把它變成程式碼我要發佈
請完整敘述操作步驟 越詳細越好
作業環境
Google試算表
Google Apps Script
我看不懂程式碼,請給我後端gs完整程式碼、前端index完整程式碼
幫我用Google 試算表建立 【無人機造型資料庫】
我希望有些資料我可以直接在試算表更改首頁可以直接呈現
需求說明 【現有產品照片、造型風格、需要有拉桿調整造型】
要把它變成程式碼我要發佈
請完整敘述操作步驟 越詳細越好
作業環境
Google試算表
Google Apps Script
我看不懂程式碼,請給我後端gs完整程式碼、前端index完整程式碼
2. 資料表規則
請照下面規則建立分頁與欄位。
第1分頁: 分頁1
A 欄: ID
B 欄: 名稱
C 欄: 造型風格
D 欄: 圖片網址
E 欄: 長度參數
F 欄: 寬度參數
G 欄: 流線度
H 欄: 圖片顯示
📄 解析結果(自動表格)
分頁:分頁1
| A 欄 | B 欄 | C 欄 | D 欄 | E 欄 | F 欄 | G 欄 | H 欄 |
|---|---|---|---|---|---|---|---|
| ID | 名稱 | 造型風格 | 圖片網址 | 長度參數 | 寬度參數 | 流線度 | 圖片顯示 |
3. 開啟 Apps Script
從試算表開 Apps Script,才能直接用 SpreadsheetApp 讀寫資料。
- 試算表上方選單:擴充功能 → Apps Script
- 刪掉預設的程式碼(或全部選取覆蓋)
-
保留/建立檔案:
- Code.gs
- index.html
4. 貼上後端(Code.gs)
把後端程式貼到 Apps Script 的 Code.gs。
/**
* 系統核心:提供網頁服務
*/
function doGet() {
return HtmlService.createTemplateFromFile('index')
.evaluate()
.setTitle('無人機造型設計系統')
.addMetaTag('viewport', 'width=device-width, initial-scale=1')
.setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL);
}
/**
* 從試算表讀取資料並自動處理圖片連結
*/
function getDroneData() {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sheet = ss.getSheetByName('Data');
if (!sheet) return [];
const data = sheet.getDataRange().getValues();
const headers = data.shift(); // 取得標題列
return data.map((row, rowIndex) => {
let obj = {};
headers.forEach((header, i) => {
let value = row[i];
// 如果是圖片網址且來自 Google Drive,自動轉換為直連格式
if (header === '圖片網址' && value.toString().includes('drive.google.com')) {
value = convertDriveLink(value.toString());
}
obj[header] = value;
});
obj['index'] = rowIndex; // 給前端標記編號用
return obj;
});
}
/**
* 內部工具:將 Google Drive 網址轉為圖片標籤可讀取的格式
*/
function convertDriveLink(url) {
var id = "";
if (url.indexOf("id=") != -1) {
id = url.split("id=")[1].split("&")[0];
} else {
var parts = url.split("/");
id = parts[parts.indexOf("d") + 1];
}
return "https://lh3.googleusercontent.com/d/" + id;
} 貼到 Apps Script 的 Code.gs 檔案
5. 貼上前端(index.html)
把前端程式貼到 Apps Script 的 index.html。
<!DOCTYPE html>
<html lang="zh-TW">
<head>
<meta charset="UTF-8">
<base target="_top">
<link href="https://cdnjs.cloudflare.com/ajax/libs/tailwindcss/2.2.19/tailwind.min.css" rel="stylesheet">
<style>
.drone-img-container {
perspective: 1000px;
background: radial-gradient(circle, #ffffff 0%, #e5e7eb 100%);
min-height: 200px;
}
.drone-preview {
transition: transform 0.1s ease-out, opacity 0.2s ease;
max-width: 100%;
max-height: 180px;
object-fit: contain;
}
.selected-card {
border: 3px solid #3b82f6 !important;
box-shadow: 0 0 15px rgba(59, 130, 246, 0.5);
}
input[type=range] {
accent-color: #3b82f6;
}
</style>
</head>
<body class="bg-gray-100 min-h-screen">
<header class="bg-gray-900 text-white p-5 shadow-xl">
<div class="container mx-auto flex justify-between items-center">
<div>
<h1 class="text-2xl font-black tracking-widest uppercase">Drone Design System</h1>
<p class="text-xs text-gray-400">無人機造型動態設計資料庫</p>
</div>
<div class="text-right text-xs">
<span class="bg-green-500 px-2 py-1 rounded text-white">系統已連線</span>
</div>
</div>
</header>
<main class="container mx-auto py-8 px-4">
<div class="flex flex-col lg:flex-row gap-8">
<div class="lg:w-1/3 space-y-6">
<div class="bg-white p-6 rounded-2xl shadow-sm border border-gray-200 sticky top-10">
<h2 class="text-lg font-bold mb-6 flex items-center">
<span class="w-2 h-6 bg-blue-600 mr-2 rounded-full"></span>
造型參數模擬調整
</h2>
<div class="space-y-8">
<div>
<div class="flex justify-between mb-2">
<label class="text-sm font-semibold text-gray-600">機身寬度比例 (Width)</label>
<span id="valW" class="text-blue-600 font-mono text-sm">100%</span>
</div>
<input type="range" id="sliderW" min="50" max="150" value="100" class="w-full">
</div>
<div>
<div class="flex justify-between mb-2">
<label class="text-sm font-semibold text-gray-600">機身長度比例 (Length)</label>
<span id="valH" class="text-blue-600 font-mono text-sm">100%</span>
</div>
<input type="range" id="sliderH" min="50" max="150" value="100" class="w-full">
</div>
<div>
<div class="flex justify-between mb-2">
<label class="text-sm font-semibold text-gray-600">機身流線度 (Opacity/Flow)</label>
<span id="valO" class="text-blue-600 font-mono text-sm">100%</span>
</div>
<input type="range" id="sliderO" min="20" max="100" value="100" class="w-full">
</div>
</div>
<div id="statusTip" class="mt-8 p-4 bg-gray-50 border border-dashed border-gray-300 rounded-lg text-sm text-gray-500 text-center">
請先點擊右側卡片「選中」<br>即可開始調整造型
</div>
</div>
</div>
<div class="lg:w-2/3">
<div id="droneList" class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div class="col-span-full py-20 text-center">
<div class="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600 mx-auto mb-4"></div>
<p class="text-gray-500 italic">正在從 Google Sheets 同步資料庫...</p>
</div>
</div>
</div>
</div>
</main>
<script>
let selectedIndex = null;
// 初始化:向後端請求資料
window.onload = () => {
google.script.run.withSuccessHandler(renderDrones).getDroneData();
};
function renderDrones(data) {
const list = document.getElementById('droneList');
list.innerHTML = '';
if (data.length === 0) {
list.innerHTML = '<p class="col-span-full text-center p-10 bg-white rounded-xl">資料庫中目前沒有資料。</p>';
return;
}
data.forEach((item) => {
const card = document.createElement('div');
card.id = `card-${item.index}`;
card.className = "bg-white rounded-2xl shadow-sm border border-gray-200 overflow-hidden cursor-pointer hover:shadow-lg transition-all";
card.onclick = () => selectDrone(item.index);
card.innerHTML = `
<div class="drone-img-container flex items-center justify-center p-6">
<img src="${item['圖片網址']}" id="drone-img-${item.index}" class="drone-preview"
onerror="this.src='https://via.placeholder.com/300x200?text=圖片讀取失敗'">
</div>
<div class="p-5">
<div class="flex justify-between items-start mb-2">
<h3 class="text-lg font-bold text-gray-800">${item['產品名稱']}</h3>
<span class="text-xs bg-blue-100 text-blue-600 px-2 py-1 rounded font-bold">${item['造型風格']}</span>
</div>
<div class="grid grid-cols-3 gap-2 text-center text-[10px] text-gray-400 uppercase mt-4">
<div class="bg-gray-50 p-2 rounded">長度: ${item['長度參數']}</div>
<div class="bg-gray-50 p-2 rounded">寬度: ${item['寬度參數']}</div>
<div class="bg-gray-50 p-2 rounded">流線: ${item['流線度']}</div>
</div>
</div>
`;
list.appendChild(card);
});
}
function selectDrone(idx) {
// 清除之前的選中狀態
if (selectedIndex !== null) {
document.getElementById(`card-${selectedIndex}`).classList.remove('selected-card');
}
// 設定新的選中狀態
selectedIndex = idx;
document.getElementById(`card-${idx}`).classList.add('selected-card');
document.getElementById('statusTip').innerHTML = `<b class="text-blue-600">已選中:正在調整無人機影像</b>`;
}
// 監聽拉桿並連動
const sW = document.getElementById('sliderW');
const sH = document.getElementById('sliderH');
const sO = document.getElementById('sliderO');
const updateTransform = () => {
if (selectedIndex === null) return;
const img = document.getElementById(`drone-img-${selectedIndex}`);
const w = sW.value;
const h = sH.value;
const o = sO.value;
// 更新顯示數值
document.getElementById('valW').innerText = w + '%';
document.getElementById('valH').innerText = h + '%';
document.getElementById('valO').innerText = o + '%';
// 即時變形圖片 (模擬造型調整)
img.style.transform = `scaleX(${w/100}) scaleY(${h/100})`;
img.style.opacity = o / 100;
};
sW.oninput = updateTransform;
sH.oninput = updateTransform;
sO.oninput = updateTransform;
</script>
</body>
</html>
貼到 Apps Script 的 index.html 檔案
6. 部署
部署成 Web App 後,就會拿到可分享網址。
- Apps Script 右上:部署 → 新部署
- 類型選:Web app
- 執行身分:你
- 存取權限:任何人
- 完成後複製網址
💬 評論區
老師們的交流與提問
登入 後即可發表評論