汽车保养记录记事本

prompt

写一个兼容PC和手机的精致好用的html保养记录记事本,记录保养时间,里程,项目,价格,可以根据年份筛选保养记录,然后根据筛选出的明细自动统计保养总花费

html 复制代码
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>车辆保养记录记事本</title>
    <script src="https://cdn.tailwindcss.com"></script>
    <link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">
    <script>
        tailwind.config = {
            theme: {
                extend: {
                    colors: {
                        primary: '#2563eb',
                        secondary: '#475569',
                    },
                    fontFamily: {
                        sans: ['Inter', 'system-ui', 'sans-serif'],
                    },
                }
            }
        }
    </script>
    <style type="text/tailwindcss">
        @layer utilities {
            .card-shadow {
                box-shadow: 0 4px 20px rgba(0,0,0,0.08);
            }
            .input-focus {
                @apply focus:ring-2 focus:ring-primary/50 focus:border-primary outline-none transition-all;
            }
        }
    </style>
</head>
<body class="bg-slate-100 min-h-screen pb-10">
<div class="max-w-5xl mx-auto px-4 py-6">
    <!-- 头部标题 -->
    <div class="bg-white rounded-xl p-6 card-shadow mb-6">
        <h1 class="text-[clamp(1.5rem,3vw,2rem)] font-bold text-slate-800 flex items-center gap-2">
            <i class="fa fa-car text-primary"></i>车辆保养记录记事本
        </h1>
        <p class="text-slate-500 mt-1">记录保养时间、里程、项目、费用,自动统计总花费</p>
    </div>
    <div class="bg-white rounded-xl p-6 card-shadow mb-6">
        <h2 class="text-lg font-semibold text-slate-700 mb-4"><i class="fa fa-plus-circle text-primary mr-2"></i>新增保养记录</h2>
        <form id="recordForm" class="grid grid-cols-1 md:grid-cols-2 gap-4">
            <div>
                <label class="block text-sm text-slate-600 mb-1">保养日期</label>
                <input type="date" id="recordDate" required class="w-full border border-slate-300 rounded-lg px-3 py-2 input-focus">
            </div>
            <div>
                <label class="block text-sm text-slate-600 mb-1">当前里程(km)</label>
                <input type="number" id="recordMileage" min="0" required placeholder="例如 125000" class="w-full border border-slate-300 rounded-lg px-3 py-2 input-focus">
            </div>
            <div class="md:col-span-2">
                <label class="block text-sm text-slate-600 mb-1">保养项目(逗号分隔)</label>
                <input type="text" id="recordItem" required placeholder="机油机滤,空滤,刹车油" class="w-full border border-slate-300 rounded-lg px-3 py-2 input-focus">
            </div>
            <div class="md:col-span-2">
                <label class="block text-sm text-slate-600 mb-1">花费金额(元)</label>
                <input type="number" id="recordCost" min="0" step="0.01" required placeholder="例如 1130" class="w-full border border-slate-300 rounded-lg px-3 py-2 input-focus">
            </div>
            <div class="md:col-span-2">
                <button type="submit" class="w-full bg-primary hover:bg-primary/90 text-white py-2.5 rounded-lg transition-all font-medium">
                    <i class="fa fa-save mr-1"></i>保存这条记录
                </button>
            </div>
        </form>
    </div>

    <div class="bg-white rounded-xl p-6 card-shadow mb-6">
        <div class="flex flex-col sm:flex-row justify-between items-start sm:items-center gap-4">
            <div>
                <label class="text-slate-600 text-sm mr-2">按年份筛选:</label>
                <select id="yearFilter" class="border border-slate-300 rounded-lg px-3 py-2 input-focus">
                    <option value="all">全部年份</option>
                </select>
            </div>
            <div class="bg-blue-50 px-4 py-3 rounded-lg">
                <span class="text-slate-700">筛选后总花费:</span>
                <span id="totalCost" class="text-xl font-bold text-primary">0.00</span>
                <span class="text-slate-600"> 元</span>
            </div>
        </div>
    </div>

    <div class="bg-white rounded-xl p-6 card-shadow">
        <h2 class="text-lg font-semibold text-slate-700 mb-4"><i class="fa fa-list-alt text-primary mr-2"></i>保养记录列表</h2>
        <div id="recordList" class="space-y-4">
            <div class="text-center text-slate-400 py-10">暂无保养记录,请添加第一条</div>
        </div>
    </div>
</div>
<script>
    // 读取本地存储
    function getRecords() {
        const data = localStorage.getItem('carMaintainRecords');
        return data ? JSON.parse(data) : [];
    }
    function saveRecords(list) {
        localStorage.setItem('carMaintainRecords', JSON.stringify(list));
    }

    // 渲染年份下拉框
    function renderYearSelect() {
        const records = getRecords();
        const yearSet = new Set();
        yearSet.add('all');
        records.forEach(item => {
            const y = new Date(item.date).getFullYear();
            yearSet.add(y);
        });
        const yearSelect = document.getElementById('yearFilter');
        const currentVal = yearSelect.value;
        yearSelect.innerHTML = '';
        Array.from(yearSet).sort((a,b)=>b-a).forEach(y=>{
            const opt = document.createElement('option');
            opt.value = y;
            opt.textContent = y === 'all' ? '全部年份' : y+'年';
            yearSelect.appendChild(opt);
        })
        yearSelect.value = currentVal;
    }

    // 渲染列表 + 计算总金额
    function renderRecords() {
        const records = getRecords();
        const selectedYear = document.getElementById('yearFilter').value;
        const listDom = document.getElementById('recordList');
        let filterList = records;

// 年份筛选
        if(selectedYear !== 'all'){
            filterList = records.filter(r=> new Date(r.date).getFullYear().toString() === selectedYear);
        }

// 计算合计
        const total = filterList.reduce((sum,item)=> sum + Number(item.cost), 0);
        document.getElementById('totalCost').innerText = total.toFixed(2);

        if(filterList.length === 0){
            listDom.innerHTML = `<div class="text-center text-slate-400 py-10">暂无记录</div>`;
            return;
        }

// 按日期倒序,新记录在最上面
        filterList.sort((a,b)=> new Date(b.date) - new Date(a.date));

        let html = '';
        filterList.forEach((item, index)=>{
            html += `
<div class="border border-slate-200 rounded-lg p-4 hover:bg-slate-50 transition">
<div class="flex justify-between items-start flex-wrap gap-2">
<div>
<div class="font-semibold text-slate-800">${item.date}</div>
<div class="text-sm text-slate-500">里程:${item.mileage} km</div>
</div>
<div class="text-primary font-bold text-lg">¥${Number(item.cost).toFixed(2)}</div>
</div>
<div class="mt-2 text-slate-600 text-sm">
<i class="fa fa-wrench text-slate-400 mr-1"></i>保养项目:${item.item}
</div>
<div class="mt-3 text-right">
<button onclick="deleteRecord(${index})" class="text-red-500 hover:text-red-700 text-sm"><i class="fa fa-trash"></i> 删除</button>
</div>
</div>
`
        })
        listDom.innerHTML = html;
    }

    // 删除记录
    window.deleteRecord = function(idx) {
        const records = getRecords();
        const selectedYear = document.getElementById('yearFilter').value;
        let filterList = records;
        if(selectedYear !== 'all'){
            filterList = records.filter(r=> new Date(r.date).getFullYear().toString() === selectedYear);
        }
// 找到原数组下标
        const targetItem = filterList[idx];
        const realIndex = records.findIndex(r=> r.date === targetItem.date && r.mileage === targetItem.mileage && r.cost === targetItem.cost);
        records.splice(realIndex,1);
        saveRecords(records);
        renderYearSelect();
        renderRecords();
    }

    // 表单提交
    document.getElementById('recordForm').addEventListener('submit', function(e){
        e.preventDefault();
        const date = document.getElementById('recordDate').value;
        const mileage = document.getElementById('recordMileage').value;
        const item = document.getElementById('recordItem').value;
        const cost = document.getElementById('recordCost').value;

        const records = getRecords();
        records.push({date, mileage, item, cost});
        saveRecords(records);
        this.reset();
        renderYearSelect();
        renderRecords();
    })

    // 年份筛选切换
    document.getElementById('yearFilter').addEventListener('change', function(){
        renderRecords();
    })

    // 初始化页面
    window.onload = function(){
// 默认日期为今天
        const today = new Date();
        const dStr = today.toISOString().split('T')[0];
        document.getElementById('recordDate').value = dStr;
        renderYearSelect();
        renderRecords();
    }
</script></body>
</html>
相关推荐
艾莉丝努力练剑3 小时前
【AI大模型接入SDK】LLM会话管理模块设计
网络·c++·人工智能·学习·大模型
虹科网络安全11 小时前
Redis 安全公告:CVE-2026-81934 TLS 处理漏洞及修复建议
网络·人工智能·网络安全
小程序设计13 小时前
某师范学院网络规划与设计
网络·安全
可爱系程序猿14 小时前
WSD 打印机时好时坏:从发现服务、地址变化到 Standard TCP/IP 端口的迁移记录
网络·网络协议·tcp/ip·程序人生·电脑
蓝速科技15 小时前
便民服务大厅 AI 数字人一体机场景适配与落地指南丨蓝速科技
大数据·网络·数据结构·人工智能·自然语言处理·数据分析·运维开发
济南凡维16 小时前
CODESOFT中如何将标签保存为PDF文件
网络·人工智能·打印机·codesoft
德迅云安全杨德俊16 小时前
高防IP:构建“防护-加速-管控”三位一体的全链路安全体系
网络·安全·ddos
猫哥随身wifi16 小时前
随身WiFi 怎么选?2026 主流品牌随身 WiFi 对比与选购避坑参考
网络·人工智能·5g·智能手机
en.en..17 小时前
TCP套接字编程 完整流程解析(服务端 + 客户端)
网络