# 通貨膨脹-台鐵便當
### 選擇原因:
* 便捷性:
適合上班族、學生和經常外出的人士,隨時隨地享用家常美食。
保溫功能強大,適合各種場合使用,如戶外活動、辦公室午餐等。
* 文化與情感價值:
台鐵便當盒在許多文化中象徵著家人的關愛和溫暖,特別是家長為孩子準備的便當中,承載著情感價值。
### SQLlit

## Code+解釋
### 前端
1. 頭部 (Head):
* 設置字符編碼為UTF-8。
* 設置視口以支持響應式設計。
* 設置頁面標題。
* 引入CSS樣式和Chart.js庫。
2. 表單 (Form):
* 包含日期選擇器(開始日期和結束日期)和便當種類選擇下拉菜單。
* 提交按鈕。
3. 畫布 (Canvas):
* 用於顯示折線圖的畫布元素。
:::spoiler **HTML**
````javascript=
<!DOCTYPE html>
<html lang="zh-Hant">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>台鐵便當價格趨勢</title>
<link rel="stylesheet" href="styles.css">
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
</head>
<body>
<form id="data-form">
<label for="startDate">開始日期:</label>
<input type="date" id="startDate" name="startDate">
<label for="endDate">結束日期:</label>
<input type="date" id="endDate" name="endDate">
<label for="bento">便當種類:</label>
<select id="bento" name="bento">
<option value="臺鐵排骨便當(經濟)">臺鐵排骨便當(經濟)</option>
<option value="古早味爌肉便當">古早味爌肉便當</option>
<option value="照燒雞丁便當">照燒雞丁便當</option>
<option value="臺鐵素食便當(白飯)">臺鐵素食便當(白飯)</option>
<option value="臺鐵素食便當(燉飯)">臺鐵素食便當(燉飯)</option>
<option value="臺鐵排骨便當(八角)">臺鐵排骨便當(八角)</option>
<option value="五行素便當">五行素便當</option>
<option value="迷迭香雞腿排便當">迷迭香雞腿排便當</option>
<option value="臺鐵雞腿便當(圓紙)">臺鐵雞腿便當(圓紙)</option>
<option value="臺鐵鯖魚便當(圓紙)">臺鐵鯖魚便當(圓紙)</option>
<option value="懷舊排骨菜飯(圓木)">懷舊排骨菜飯(圓木)</option>
<option value="客家紅麴雞便當">客家紅麴雞便當</option>
<option value="薑汁燒肉飯">薑汁燒肉飯</option>
<option value="芋香牛蒡飯">芋香牛蒡飯</option>
</select>
<button type="submit">提交</button>
</form>
<canvas id="myChart"></canvas>
<script>
document.getElementById('data-form').addEventListener('submit', function(event) {
event.preventDefault();
const startDate = document.getElementById('startDate').value;
const endDate = document.getElementById('endDate').value;
const bento = document.getElementById('bento').value;
fetch(`/api/prices?startDate=${startDate}&endDate=${endDate}&bento=${bento}`)
.then(response => {
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.json();
})
.then(data => {
const dates = data.prices.map(price => new Date(price.date));
const prices = data.prices.map(price => price.price);
drawChart(dates, prices);
})
.catch(error => {
console.error('Error:', error);
// Handle the error
});
});
function drawChart(dates, prices) {
const ctx = document.getElementById('myChart').getContext('2d');
if (window.myChart) {
window.myChart.destroy();
}
window.myChart = new Chart(ctx, {
type: 'line',
data: {
labels: dates,
datasets: [{
label: 'Price Trend',
data: prices,
borderColor: 'rgb(75, 192, 192)',
tension: 0.1
}]
},
options: {
scales: {
x: {
type: 'time',
time: {
unit: 'month',
displayFormats: {
month: 'YYYY-MM'
}
},
title: {
display: true,
text: 'Time'
}
},
y: {
title: {
display: true,
text: 'Price'
}
}
}
}
});
}
</script>
</body>
</html>
````
:::
### 後端
1. 引入套件:
* express: 這是一個流行的 Node.js Web 框架,用於處理 HTTP 請求和路由。
* path: Node.js 的內置模組,用於處理文件路徑。
* sqlite3: 這是 SQLite 資料庫的 Node.js 綁定,用於操作 SQLite 資料庫。
* cors: 這是一個 Express 中間件,用於處理跨來源資源共享(CORS)。
2. 建立 Express 應用程式實例:
* 使用 express() 建立了一個 Express 應用程式。
3. 設置中間件:
* cors():啟用 CORS 支持,允許跨來源請求。
4. 連接資料庫:
* 使用 sqlite3 打開 SQLite 資料庫連接。
* 如果連接成功,則創建一個名為 bento_prices 的資料表,該表包含 id、date、bento_type 和 price 欄位。
5. 定義路由:
* GET /api/prices:當收到此路由的 GET 請求時,使用提供的查詢參數(startDate、endDate 和 bento)從資料庫中檢索對應的價格資料。
* 如果查詢成功,將結果以 JSON 格式返回,並將日期格式化為 ISO 8601 標準。
6. 設置靜態資源路徑:
* 使用 express.static 中間件指定了靜態資源的路徑,這將使 Express 伺服器能夠提供靜態檔案(如 HTML、CSS、JavaScript)。
7. 啟動伺服器:
* 使用 app.listen() 啟動了一個 HTTP 伺服器,監聽在本地端口 3000 上。
:::spoiler **app.js**
````javascript=
const express = require('express');
const path = require('path');
const sqlite3 = require('sqlite3').verbose();
const cors = require('cors');
const app = express();
app.use(cors());
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
const dbPath = path.join(__dirname, 'db', 'sqlite.db');
const db = new sqlite3.Database(dbPath, (err) => {
if (err) {
console.error('Error connecting to database:', err.message);
} else {
console.log('Connected to SQLite database:', dbPath);
db.run(`CREATE TABLE IF NOT EXISTS bento_prices (
id INTEGER PRIMARY KEY AUTOINCREMENT,
date DATE NOT NULL,
bento_type TEXT NOT NULL,
price REAL NOT NULL
)`, (err) => {
if (err) {
console.error('Error creating bento_prices table:', err.message);
} else {
console.log('bento_prices table created successfully.');
}
});
}
});
// 查询价格趋势
app.get('/api/prices', (req, res) => {
const { startDate, endDate, bento } = req.query;
const sql = `
SELECT date, price
FROM bento_prices
WHERE bento_type = ? AND date BETWEEN ? AND ?
ORDER BY date
`;
db.all(sql, [bento, startDate, endDate], (err, rows) => {
if (err) {
console.error('Error executing query:', err.message);
res.status(500).json({ error: err.message });
return;
}
console.log('Query results:', rows);
// 格式化日期為 ISO 8601 格式
const formattedRows = rows.map(row => ({
date: new Date(row.date).toISOString(),
price: parseFloat(row.price)
}));
res.json({ prices: formattedRows });
});
});
app.use(express.static(path.join(__dirname, 'public')));
const PORT = 3000;
app.listen(PORT, () => {
console.log(`Server running at http://localhost:${PORT}`);
});
module.exports = app;
````
:::