namespace ConsoleApp1
{
internal class Program
{
static void Main(string[] args)
{
int 總出貨數量 = 24;
int 預計包裝數量 = 5;
// 傳統寫法一:/ 搭配 %
int 實際包裝數量_1 = 總出貨數量 / 預計包裝數量;
int 剩餘數量_1 = 總出貨數量 % 預計包裝數量;
if (剩餘數量_1 > 0)
實際包裝數量_1++;
// 傳統寫法二:Math.Ceiling 無條件進位
int 實際包裝數量2 = (int)Math.Ceiling((double)總出貨數量 / 預計包裝數量);
// .NET Framework:透過 out 回傳剩餘數量
int 實際包裝數量_3 = Math.DivRem(總出貨數量, 預計包裝數量, out int 剩餘數量_3);
if (剩餘數量_3 > 0)
實際包裝數量_3++;
// .NET 6 新增:使用 Tuple 回傳
var (實際包裝數量_4, 剩餘數量_4) = Math.DivRem(總出貨數量, 預計包裝數量);
if (剩餘數量_4 > 0)
實際包裝數量_4++;
Console.WriteLine($"/ 搭配 %: {實際包裝數量_1}");
Console.WriteLine($"Math.Ceiling 無條件進位: {實際包裝數量2}");
Console.WriteLine($"透過 out 回傳剩餘數量: {實際包裝數量_3}");
Console.WriteLine($"使用 Tuple 回傳: {實際包裝數量_4}");
}
}
}
~楓花雪岳~
星期四, 5月 21, 2026
[C#] Math.DivRem
以商業邏輯出貨包裝數量為例子來記錄不同計算寫法
星期二, 5月 19, 2026
[GAS] Utilities.getUuid()
AI 產出 Code 在 js 刪除 Google Sheet 資料時,常常會看見把資料反向排序後,再依序刪除做法,避免破壞 Google Sheet RowPosition,想說要給在新增資料時給定唯一識別碼,發現 GAS 內建就有 Utilities.getUuid() 可以使用,這樣就可以明確直接刪除特定資料
星期六, 5月 16, 2026
[GAS] OTP 登錄
在了解 [GAS] CacheService 如何使用後,該筆記範例是 OTP 登錄範例,OTP (One Time Password) 相關操作都會在 CacheService 上進行
gs Code
收到 OTP email
使用 OTP 密碼登錄
Index.html 不是該筆記重點,就不放在文章上囉
gs Code
/**
* 處理 Web App 的 HTTP GET 請求,回傳使用者介面。
* @param {Object} e - 事件物件 (GET 參數)。
* @return {HtmlOutput} 渲染後的 HTML 畫面。
*/
function doGet(e) {
return HtmlService.createHtmlOutputFromFile('Index')
.setTitle('OTP 登入')
.setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL);
}
/**
* 產生並發送 OTP 至指定 Email,同時將 OTP 寫入 CacheService。
* @param {string} email - 使用者的電子郵件地址。
* @return {Object} 包含執行結果的狀態物件 {success: boolean, message: string}。
*/
function generateAndSendOTP(email) {
try {
if (!email || !email.includes('@')) {
return { success: false, message: '請提供有效的 Email 地址格式' };
}
// 產生 6 位數隨機 OTP
const otp = Math.floor(100000 + Math.random() * 900000).toString();
// 取得 Script 層級的 Cache,將 email 當作 Key,OTP 當作 Value
const cache = CacheService.getScriptCache();
// 設定快取保留時間為 300 秒 (5 分鐘)
cache.put(email, otp, 300);
// 寄送包含 OTP 的電子郵件
const subject = '您的系統登入一次性密碼 (OTP)';
const body = '您好,\n\n您的登入驗證碼為:' + otp + '\n此驗證碼將於 5 分鐘後失效。\n\n若非本人操作請忽略此信件。';
GmailApp.sendEmail(email, subject, body);
return { success: true, message: 'OTP 已發送至您的信箱,請於 5 分鐘內輸入。' };
} catch (error) {
return { success: false, message: '系統錯誤:' + error.message };
}
}
/**
* 驗證使用者輸入的 OTP 是否與 CacheService 中的記錄相符。
* @param {string} email - 使用者的電子郵件地址。
* @param {string} otp - 使用者輸入的 OTP。
* @return {Object} 包含驗證結果的狀態物件 {success: boolean, message: string}。
*/
function verifyOTP(email, otp) {
try {
const cache = CacheService.getScriptCache();
const cachedOtp = cache.get(email);
if (!cachedOtp) {
return { success: false, message: 'OTP 已過期或不存在,請重新獲取。' };
}
if (cachedOtp === otp) {
// 驗證成功後,基於安全性應立即移除 Cache 中的 OTP
cache.remove(email);
return { success: true, message: '驗證成功!歡迎登入系統。' };
} else {
return { success: false, message: 'OTP 錯誤,請重新輸入。' };
}
} catch (error) {
return { success: false, message: '驗證時發生系統錯誤:' + error.message };
}
}
執行結果
收到 OTP email
使用 OTP 密碼登錄
Index.html 不是該筆記重點,就不放在文章上囉
星期二, 5月 12, 2026
[SQL] 轉型為 bit
無意中在自家系統內看見下述 TSQL 語法,整數 2 轉型 bit 竟然不會出現轉型錯誤
SELECT CAST(2 as bit)
在官方文件 - bit 內有這段說明
The bit data type can be used to store Boolean values. The string values TRUE and FALSE can be converted to bit values: TRUE is converted to 1, and FALSE is converted to 0.基本上只要不是 0 就是轉型為 1 就是,測試範例如下
Converting to bit promotes any nonzero value to 1.
The bit data type supports the COUNT function. However, other standard aggregate functions, like SUM, AVG, MIN, and MAX, don't directly support the bit data type.
SELECT
source as 整數 ,
CAST(source as bit) AS 整數轉型bit
FROM
(
SELECT 0 AS source UNION ALL
SELECT 1 UNION ALL
SELECT 2 UNION ALL
SELECT 100 UNION ALL
SELECT -1
) AS T
星期六, 5月 09, 2026
[GAS] clasp deploy
部屬官方文件說明
A release that makes a specific version of your script available for users. A deployment has a unique URL or ID.
GAS IDE 部屬有三種模式,分別為
- 新增部屬作業:詳見 [GAS] 部屬網頁程式
- 管理部屬作業:詳見 [GAS] 管理部屬作業
- 測試部屬作業:未部屬狀態下可以執行 Code,會得到一個 dev 結尾網址,該位址不會變化,Code 有進行任何更改的話,可以在瀏覽器上按 F5 refresh 執行程式
而 claps deploy 有兩種語法應用
- clasp deploy 對應 [新增部屬作業],部屬後每次都會取得一個新的網址
- clasp deploy --deploymentId <deployment-id> 對應 [管理部屬作業],部屬後網址不變
訂閱:
文章 (Atom)






