![]()
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>智能油耗追踪器</title>
<style>
:root {
--primary: #3b82f6;
--error: #ef4444;
--success: #10b981;
--bg: #f8fafc;
}
body {
font-family: system-ui, -apple-system, sans-serif;
max-width: 600px;
margin: 0 auto;
padding: 1rem;
background-color: var(--bg);
}
.container {
background: white;
padding: 1.5rem;
border-radius: 1rem;
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
}
.input-grid {
display: grid;
gap: 1rem;
grid-template-columns: repeat(2, 1fr);
margin-bottom: 1.5rem;
}
.input-group {
position: relative;
}
label {
display: block;
margin-bottom: 0.5rem;
color: #1e293b;
font-size: 0.875rem;
font-weight: 500;
}
input {
width: 100%;
padding: 0.75rem;
border: 1px solid #e2e8f0;
border-radius: 0.5rem;
font-size: 1rem;
transition: all 0.2s;
}
input:focus {
border-color: var(--primary);
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
outline: none;
}
.error-msg {
color: var(--error);
font-size: 0.75rem;
margin-top: 0.25rem;
display: none;
}
.btn {
background: var(--primary);
color: white;
padding: 0.875rem;
border: none;
border-radius: 0.5rem;
width: 100%;
font-size: 1rem;
cursor: pointer;
transition: background 0.2s;
}
.btn:hover {
background: #2563eb;
}
.result-card {
margin-top: 1.5rem;
padding: 1.25rem;
background: #eff6ff;
border-radius: 0.75rem;
display: none;
}
.history-section {
margin-top: 2rem;
}
.history-item {
background: white;
padding: 1rem;
margin-bottom: 1rem;
border-radius: 0.5rem;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
position: relative;
}
.delete-btn {
position: absolute;
top: 0.5rem;
right: 0.5rem;
color: var(--error);
cursor: pointer;
padding: 0.25rem;
}
.timestamp {
color: #64748b;
font-size: 0.75rem;
margin-bottom: 0.5rem;
}
@media (max-width: 480px) {
.input-grid {
grid-template-columns: 1fr;
}
}
</style>
</head>
<body>
<div class="container">
<div class="input-grid">
<div class="input-group">
<label>加油金额(元)</label>
<input type="number" id="amount" step="0.01" min="0">
<div class="error-msg" id="amount-error"></div>
</div>
<div class="input-group">
<label>油价(元/升)</label>
<input type="number" id="price" step="0.01" min="0">
<div class="error-msg" id="price-error"></div>
</div>
<div class="input-group">
<label>当前里程(km)</label>
<input type="number" id="current" step="1" min="0">
<div class="error-msg" id="current-error"></div>
</div>
<div class="input-group">
<label>上次里程(km)</label>
<input type="number" id="last" step="1" min="0">
<div class="error-msg" id="last-error"></div>
</div>
</div>
<button class="btn" onclick="calculate()">立即计算</button>
<div class="result-card" id="result">
<p>行驶距离:<span id="mileage">0</span> km</p>
<p>百公里油耗:<span id="consumption">0</span> L</p>
<p>每公里成本:<span id="cost">0</span> 元</p>
</div>
<div class="history-section">
<h3>历史记录</h3>
<div id="history"></div>
</div>
</div>
<script>
const STORAGE_KEY = 'fuelHistory';
let history = JSON.parse(localStorage.getItem(STORAGE_KEY)) || [];
// 初始化上次里程
function initLastMileage() {
const lastInput = document.getElementById('last');
if (history.length > 0) {
lastInput.value = history[0].currentMileage;
}
}
// 输入验证
function validate() {
let isValid = true;
const inputs = {
amount: parseFloat(document.getElementById('amount').value),
price: parseFloat(document.getElementById('price').value),
current: parseFloat(document.getElementById('current').value),
last: parseFloat(document.getElementById('last').value)
};
document.querySelectorAll('.error-msg').forEach(el => el.style.display = 'none');
// 验证逻辑
if (isNaN(inputs.amount) || inputs.amount <= 0) {
showError('amount-error', '请输入有效金额');
isValid = false;
}
if (isNaN(inputs.price) || inputs.price <= 0) {
showError('price-error', '请输入有效油价');
isValid = false;
}
if (isNaN(inputs.current) || inputs.current <= 0) {
showError('current-error', '请输入有效里程');
isValid = false;
}
if (isNaN(inputs.last) || inputs.last < 0) {
showError('last-error', '请输入有效里程');
isValid = false;
}
if (inputs.current <= inputs.last) {
showError('current-error', '当前里程必须大于上次里程');
isValid = false;
}
return isValid;
}
function showError(elementId, message) {
const el = document.getElementById(elementId);
el.textContent = message;
el.style.display = 'block';
}
function calculate() {
if (!validate()) return;
const record = {
timestamp: new Date().toISOString(),
amount: parseFloat(document.getElementById('amount').value),
price: parseFloat(document.getElementById('price').value),
currentMileage: parseFloat(document.getElementById('current').value),
lastMileage: parseFloat(document.getElementById('last').value),
mileage: 0,
consumption: 0,
costPerKm: 0
};
// 计算结果
record.mileage = record.currentMileage - record.lastMileage;
record.consumption = (record.amount / record.price / record.mileage * 100).toFixed(2);
record.costPerKm = (record.amount / record.mileage).toFixed(2);
// 显示结果
document.getElementById('result').style.display = 'block';
document.getElementById('mileage').textContent = record.mileage;
document.getElementById('consumption').textContent = record.consumption;
document.getElementById('cost').textContent = record.costPerKm;
// 保存记录
history.unshift(record);
localStorage.setItem(STORAGE_KEY, JSON.stringify(history));
updateHistory();
initLastMileage(); // 更新下次的上次里程
}
function deleteRecord(index) {
history.splice(index, 1);
localStorage.setItem(STORAGE_KEY, JSON.stringify(history));
updateHistory();
initLastMileage(); // 更新显示的上次里程
}
function updateHistory() {
const historyEl = document.getElementById('history');
historyEl.innerHTML = history.map((record, index) => `
<div class="history-item">
<span class="delete-btn" onclick="deleteRecord(${index})">✕</span>
<div class="timestamp">${new Date(record.timestamp).toLocaleString()}</div>
<p>里程:${record.lastMileage} → ${record.currentMileage}km</p>
<p>油耗:${record.consumption}L/100km</p>
<p>成本:¥${record.costPerKm}/km</p>
</div>
`).join('');
}
// 初始化
initLastMileage();
updateHistory();
</script>
</body>
</html>
![]()