Skip to content

Commit 449186e

Browse files
committed
feat: 驗證場景3修復完成,統計和CSV導出功能正常運作
1 parent 5331c85 commit 449186e

2 files changed

Lines changed: 75 additions & 6 deletions

File tree

demos/02-completed/js/utils.js

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,16 @@ function formatCurrency(amount) {
66
return `NT$ ${amount.toLocaleString('zh-TW')}`;
77
}
88

9-
// 計算運費
10-
// 滿 1000 元免運費,否則收取 60 元
9+
// 計算運費 (課程中新增的階梯式運費)
10+
// 500以下60元,500-1000收30元,1000以上免運
1111
function calculateShipping(subtotal) {
12-
const FREE_SHIPPING_THRESHOLD = 1000;
13-
const SHIPPING_FEE = 60;
14-
15-
return subtotal >= FREE_SHIPPING_THRESHOLD ? 0 : SHIPPING_FEE;
12+
if (subtotal >= 1000) {
13+
return 0; // 1000以上免運
14+
} else if (subtotal >= 500) {
15+
return 30; // 500-1000收30元
16+
} else {
17+
return 60; // 500以下60元
18+
}
1619
}
1720

1821
// 產生唯一 ID

demos/03-completed/data-processor.js

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,72 @@ function calculateStats(data, columnName) {
100100
};
101101
}
102102

103+
// ========================================
104+
// ✅ 課程中生成的統計函數 (步驟4)
105+
// ========================================
106+
function calculateStatistics(numbers) {
107+
if (!Array.isArray(numbers) || numbers.length === 0) {
108+
return { average: 0, median: 0, max: 0, min: 0 };
109+
}
110+
111+
// 過濾並轉換為數字
112+
const validNumbers = numbers.filter(n => !isNaN(n) && n !== null && n !== undefined);
113+
114+
if (validNumbers.length === 0) {
115+
return { average: 0, median: 0, max: 0, min: 0 };
116+
}
117+
118+
// 計算平均值
119+
const average = validNumbers.reduce((sum, num) => sum + Number(num), 0) / validNumbers.length;
120+
121+
// 計算中位數
122+
const sortedNumbers = [...validNumbers].map(Number).sort((a, b) => a - b);
123+
const median = sortedNumbers.length % 2 === 0
124+
? (sortedNumbers[sortedNumbers.length / 2 - 1] + sortedNumbers[sortedNumbers.length / 2]) / 2
125+
: sortedNumbers[Math.floor(sortedNumbers.length / 2)];
126+
127+
// 計算最大值和最小值
128+
const max = Math.max(...sortedNumbers);
129+
const min = Math.min(...sortedNumbers);
130+
131+
return {
132+
average: Number(average.toFixed(2)),
133+
median: Number(median.toFixed(2)),
134+
max: max,
135+
min: min
136+
};
137+
}
138+
139+
// ========================================
140+
// ✅ 課程中生成的導出函數 (步驟5)
141+
// ========================================
142+
function exportToCSV(data) {
143+
if (!Array.isArray(data) || data.length === 0) {
144+
return '';
145+
}
146+
147+
// 獲取所有可能的欄位名稱
148+
const headers = Object.keys(data[0]);
149+
150+
// 創建 CSV 標題行
151+
const csvHeaders = headers.join(',');
152+
153+
// 創建 CSV 數據行
154+
const csvRows = data.map(row => {
155+
return headers.map(header => {
156+
const value = row[header];
157+
// 處理包含逗號或引號的值
158+
if (typeof value === 'string' && (value.includes(',') || value.includes('"'))) {
159+
return `"${value.replace(/"/g, '""')}"`;
160+
}
161+
return value || '';
162+
}).join(',');
163+
});
164+
165+
// 組合完整的 CSV 字串
166+
return [csvHeaders, ...csvRows].join('\n');
167+
}
168+
103169
// ========================================
104170
// 展示所有功能
105171
// ========================================

0 commit comments

Comments
 (0)