SyntaxError: Unexpected token ';' (第 18 行,檔案名稱:程式碼)該範例就單純在 code.gs 內的參數傳遞至 Index.html 而已,因為錯誤訊息一直指向 code.gs 內,所以第一時間也沒有意識到錯誤是在 Index.html 內,都修錯方向
部屬執行後都出現下面錯誤訊息
錯誤竟然在 Index.html 內的註解,傻眼
正確應該是下圖才是,這樣才會正確解析 < 和 > 符號,但這是註解說,本來就沒有要顯示,真的打在有趣的點
SyntaxError: Unexpected token ';' (第 18 行,檔案名稱:程式碼)該範例就單純在 code.gs 內的參數傳遞至 Index.html 而已,因為錯誤訊息一直指向 code.gs 內,所以第一時間也沒有意識到錯誤是在 Index.html 內,都修錯方向
Gets the cache instance scoped to the script. Script caches are common to all users of the script. Use these to store information that is not specific to the current user.CacheServide 最多儲存 1,000 筆,超過 1,000 筆的話會保留 expirationInSeconds 最長的 900 筆資料
/**
* 示範 Google Apps Script 的 CacheService 混合寫入操作
* 包含 putAll (批量新增)、put (單筆新增)、getAll (批量讀取)、刪除與驗證
* * @returns {void}
*/
function demoCacheServiceMixedCRUD() {
// 1. 初始化 ScriptCache
const cache = CacheService.getScriptCache();
// 2. 使用 putAll() 批量新增三筆資料
// 將快取資料整理成一個 Object (KeyValue)
const batchData = {
'user_01': 'Alice',
'user_02': 'Bob',
'user_03': 'Charlie'
};
// 寫入批次資料,設定存活時間為 600 秒 (預設值)
cache.putAll(batchData, 600);
console.log('✅ 已使用 putAll() 成功新增三筆資料至 Cache。');
// 3. 使用 put() 追加新增單一筆資料
const singleKey = 'user_04';
cache.put(singleKey, 'David', 600);
console.log(`✅ 已使用 put() 成功追加一筆資料至 Cache:${singleKey}`);
// 4. 取得全部資料 (Read)
// 將批次寫入的 keys 與單筆寫入的 key 合併成一個陣列來查詢
const allKeysToFetch = ['user_01', 'user_02', 'user_03', 'user_04'];
const allData = cache.getAll(allKeysToFetch);
console.log('🔍 取得目前的資料狀態:', allData);
// 5. 移除一筆資料 (Delete)
const targetToRemove = 'user_02'; // 準備移除 Bob
cache.remove(targetToRemove);
console.log(`🗑️ 已執行移除動作,目標:${targetToRemove}`);
// 6. 取得上一筆移除資料,驗證該筆資料已不存在
const removedData = cache.get(targetToRemove);
if (removedData === null) {
console.log(`⚠️ 驗證成功:${targetToRemove} 已經被移除 (查詢結果為 null)。`);
} else {
console.log(`❌ 錯誤:${targetToRemove} 依然存在,值為:`, removedData);
}
}
put(key, value, expirationInSeconds)Sparse columns are ordinary columns that have an optimized storage for null values. Sparse columns reduce the space requirements for null values at the cost of more overhead to retrieve non-NULL values. Consider using sparse columns when the space saved is at least 20 percent to 40 percent.Sparse 關鍵字
USE AdventureWorks2025;
GO
CREATE TABLE DocumentStore
(DocID int PRIMARY KEY,
Title varchar(200) NOT NULL,
ProductionSpecification varchar(20) SPARSE NULL, -- SPARSE Column
ProductionLocation smallint SPARSE NULL, -- SPARSE Column
MarketingSurveyGroup varchar(20) SPARSE NULL ) ; -- SPARSE Column
GO
Sparse Column 查詢
use AdventureWorks2025
go
SELECT
[name] AS ColumnName ,
is_nullable ,
is_sparse ,
is_column_set
FROM sys.columns
WHERE object_name(object_id) = 'DocumentStore'
限制Gets information about the current user. If security policies do not allow access to the user's identity, User.getEmail() returns a blank string. The circumstances in which the email address is available vary: for example, the user's email address is not available in any context that allows a script to run without that user's authorization, like a simple onOpen(e) or onEdit(e) trigger, a custom function in Google Sheets, or a web app deployed to "execute as me" (that is, authorized by the developer instead of the user). However, these restrictions generally do not apply if the developer runs the script themselves or belongs to the same Google Workspace domain as the user.
/**
* 系統配置參數
* @constant {Object}
*/
const CONFIG = {
PROPERTY_KEY: 'WHITELIST' // 儲存在指令碼屬性中的鍵名
};
/**
* 從指令碼屬性 (PropertiesService) 中獲取白名單。
* @returns {string[]} 允許存取的 Google 帳號信箱陣列。
*/
const getAllowedEmails = () => {
const whitelistStr = PropertiesService.getScriptProperties().getProperty(CONFIG.PROPERTY_KEY);
if (!whitelistStr) {
console.warn('目前沒有設定任何白名單。');
return [];
}
// 將字串轉為陣列,過濾空白並轉為小寫
return whitelistStr.split(',')
.map(email => email.trim().toLowerCase())
.filter(email => email !== '');
};
/**
* 處理 Web App 的 HTTP GET 請求。
* @param {Object} e - 事件物件。
* @returns {GoogleAppsScript.HTML.HtmlOutput} 根據使用者權限回傳對應的 HTML 頁面。
*/
const doGet = (e) => {
const currentUserEmail = Session.getActiveUser().getEmail().toLowerCase();
const allowedEmails = getAllowedEmails();
if (allowedEmails.includes(currentUserEmail)) {
// 驗證通過
const template = HtmlService.createTemplateFromFile('Index');
template.userEmail = currentUserEmail;
return template.evaluate().setTitle('系統主控台');
} else {
// 驗證失敗
const template = HtmlService.createTemplateFromFile('Error');
template.userEmail = currentUserEmail;
return template.evaluate().setTitle('存取被拒絕');
}
};
Index.html 和 Error.html 就不特別列出來囉
/**
* 將指定的 Google Doc 文件轉換為 PDF,並儲存到指定的 Google Drive 資料夾中
*
* @param {string} documentId - 欲轉換的 Google Doc 檔案 ID
* @param {string} folderId - 儲存 PDF 的目標資料夾 ID
* @returns {string} 新建立的 PDF 檔案 URL
* @throws {Error} 當缺少必要參數、找不到檔案、權限不足或轉換失敗時拋出錯誤
*/
function convertDocToPdf(documentId, folderId) {
if (!documentId || !folderId) {
throw new Error("執行失敗:必須同時提供 documentId (文件 ID) 與 folderId (目標資料夾 ID)。");
}
try {
// 1. 透過 ID 取得指定的 Google 文件
const docFile = DriveApp.getFileById(documentId);
// 2. 將檔案轉換為 PDF 格式的 Blob (二進位大型物件)
const pdfBlob = docFile.getAs(MimeType.PDF);
// 3. 設定產出的 PDF 檔名 (預設為原檔名加上 .pdf)
const newFileName = `${docFile.getName()}.pdf`;
pdfBlob.setName(newFileName);
// 4. 取得目標資料夾實體,並在該資料夾內直接建立 PDF 檔案
const folder = DriveApp.getFolderById(folderId);
const newPdfFile = folder.createFile(pdfBlob);
return newPdfFile.getUrl();
} catch (error) {
throw new Error(`PDF 轉換程序發生錯誤: ${error.message}`);
}
}
執行
function testConvertDocToPdf() {
const targetDocumentId = "1x17o_MEpEU-S2jKzFhdVqfQ3bswGVPKf2ottem8TSRE";
const targetFolderId = "1Odq3pbNO63RxXmrxWNM9vSGWuGWyBmbZ";
try {
const pdfUrl = convertDocToPdf(targetDocumentId, targetFolderId);
console.log(`轉換完成!PDF 檔案已儲存至指定資料夾,連結請見: ${pdfUrl}`);
} catch (error) {
console.error(error);
}
}