首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >万能工具大全——简单记账本

万能工具大全——简单记账本

作者头像
红目香薰
发布2025-12-16 15:18:36
发布2025-12-16 15:18:36
90
举报
文章被收录于专栏:CSDNToQQCodeCSDNToQQCode
在这里插入图片描述
在这里插入图片描述

前言

我们可以通过算法来完成很多很多的功能,所以就有了一个想法,将各类工具都写出来,当然是尽可能的,毕竟未来无限可期,很多功能是我们当前还想不到的,为了最为靠谱的方法来完成,这里选择的语言为 HTML 来完成,别看只是简单的页面操作,但是里面都是各类算法来完成的,并且有很多的js库,做起来会很方便,能节约很多的时间,本系列文章会很多,有些标题命名可能不太合适,如果你用到了,感觉不好找可以在文章下面留言,我看到了后会进行对应的修改,希望本系列文章能给大家提供到各种各样的遍历。

简单记账本功能说明

系统概述

简单记账本是一款轻量级的个人财务管理工具,旨在帮助用户轻松记录日常收支,并通过直观的数据可视化功能,提供清晰的财务状况分析。该应用采用现代化的界面设计,操作简便,适合各类用户使用。

核心功能

1. 收支记录管理
  • 快速记账:通过"记一笔"按钮,快速添加收入或支出记录
  • 双向记账:支持收入和支出两种类型的记账方式
  • 分类管理:预设多种收入和支出分类,便于财务分析
  • 日期记录:可选择任意日期进行记账,支持补录历史交易
  • 备注功能:为每笔交易添加详细说明,便于后期查询
2. 交易记录查看
  • 交易列表:按时间倒序展示所有交易记录
  • 类型筛选:可筛选查看全部、仅收入或仅支出的交易记录
  • 时间筛选:支持按本月、本周、今天进行时间范围筛选
  • 删除功能:可删除任意历史交易记录
3. 财务统计分析
  • 月度汇总:显示本月总收入、总支出和结余情况
  • 分类统计:通过饼图直观展示收入和支出的分类占比
  • 趋势分析:通过折线图展示近6个月的收支变化趋势
  • 实时更新:数据变更后自动更新所有统计图表
4. 数据可视化
  • 收入分类图:直观展示各类收入的占比情况
  • 支出分类图:清晰呈现各类支出的比例分布
  • 月度趋势图:展示近半年的收入和支出变化趋势
  • 交互式图表:支持图表悬停查看详细数据
5. 本地数据存储
  • 自动保存:所有交易记录自动保存到本地浏览器存储
  • 数据持久化:关闭浏览器后数据不会丢失
  • 隐私保护:数据仅存储在本地,不会上传到服务器

使用方法

记录新交易
  1. 点击页面顶部的"记一笔"按钮
  2. 选择交易类型(收入或支出)
  3. 输入交易金额
  4. 选择适当的分类
  5. 设置交易日期(默认为今天)
  6. 添加备注信息(可选)
  7. 点击"保存"按钮完成记录
查看和筛选交易
  1. 在"收支明细"卡片中查看所有交易记录
  2. 使用"筛选"下拉菜单选择查看全部、仅收入或仅支出
  3. 点击"本月"、"本周"或"今天"按钮筛选不同时间范围的交易
  4. 点击交易记录右侧的删除按钮可删除该条记录
分析财务状况
  1. 查看页面顶部卡片了解本月收入、支出和结余情况
  2. 通过右侧的饼图分析收入和支出的分类分布
  3. 通过底部的趋势图了解近6个月的收支变化趋势

技术特点

  • 响应式设计:适配各种屏幕尺寸,提供良好的移动端体验
  • 本地存储:使用浏览器localStorage保存数据,无需注册账号
  • 图表可视化:使用Chart.js提供专业的数据图表展示
  • Bootstrap界面:采用Bootstrap 5框架,界面美观现代
  • 无需联网:完全基于客户端运行,无需服务器支持

数据安全

  • 所有数据仅存储在用户本地浏览器中
  • 不会上传至任何服务器,保护用户隐私
  • 清除浏览器缓存会导致数据丢失,建议定期备份重要数据

系统要求

  • 支持现代浏览器:Chrome、Firefox、Safari、Edge等
  • 需启用JavaScript和localStorage
  • 建议使用最新版本浏览器以获得最佳体验

核心代码

代码语言:javascript
复制
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>简单记账本</title>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css">
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.0/font/bootstrap-icons.css">
    <style>
        :root {
            --primary-color: #6eb48c;
            --secondary-color: #f5f8f6;
            --accent-color: #4a9e76;
            --text-color: #333;
            --light-text: #666;
            --border-radius: 10px;
            --box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
        }
        
        body {
            font-family: 'PingFang SC', 'Microsoft YaHei', sans-serif;
            background-color: #f8f9fa;
            color: var(--text-color);
            line-height: 1.6;
        }
        
        .header {
            background-color: white;
            box-shadow: var(--box-shadow);
            padding: 1.5rem 0;
            margin-bottom: 2rem;
        }
        
        .header h1 {
            color: var(--primary-color);
            font-weight: 600;
        }
        
        .container {
            max-width: 1200px;
        }
        
        .card {
            border: none;
            border-radius: var(--border-radius);
            box-shadow: var(--box-shadow);
            transition: transform 0.3s ease;
            margin-bottom: 1.5rem;
            overflow: hidden;
        }
        
        .card:hover {
            transform: translateY(-5px);
        }
        
        .card-header {
            background-color: var(--primary-color);
            color: white;
            font-weight: 600;
            padding: 0.8rem 1.2rem;
        }
        
        .btn-primary {
            background-color: var(--primary-color);
            border-color: var(--primary-color);
        }
        
        .btn-primary:hover {
            background-color: var(--accent-color);
            border-color: var(--accent-color);
        }
        
        .btn-outline-primary {
            color: var(--primary-color);
            border-color: var(--primary-color);
        }
        
        .btn-outline-primary:hover {
            background-color: var(--primary-color);
            color: white;
        }
        
        .transaction-item {
            border-left: 4px solid transparent;
            background-color: white;
            padding: 1rem;
            margin-bottom: 0.5rem;
            border-radius: var(--border-radius);
            box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
            transition: all 0.2s ease;
        }
        
        .transaction-item:hover {
            box-shadow: var(--box-shadow);
        }
        
        .transaction-item.income {
            border-left-color: #28a745;
        }
        
        .transaction-item.expense {
            border-left-color: #dc3545;
        }
        
        .amount {
            font-weight: 600;
        }
        
        .income .amount {
            color: #28a745;
        }
        
        .expense .amount {
            color: #dc3545;
        }
        
        .category-badge {
            display: inline-block;
            padding: 0.25rem 0.5rem;
            border-radius: 20px;
            font-size: 0.75rem;
            font-weight: 600;
            background-color: var(--secondary-color);
            color: var(--primary-color);
        }
        
        .footer {
            background-color: white;
            padding: 2rem 0;
            margin-top: 3rem;
            box-shadow: 0 -4px 12px rgba(0, 0, 0, 0.05);
        }
        
        .footer p {
            margin-bottom: 0;
            color: var(--light-text);
        }
        
        .summary-card {
            text-align: center;
            padding: 1.5rem;
        }
        
        .summary-value {
            font-size: 1.8rem;
            font-weight: bold;
            display: block;
            margin: 0.5rem 0;
        }
        
        .income-value {
            color: #28a745;
        }
        
        .expense-value {
            color: #dc3545;
        }
        
        .balance-value {
            color: var(--primary-color);
        }
        
        .chart-container {
            position: relative;
            height: 300px;
            margin-bottom: 1.5rem;
        }
        
        .date-filter {
            display: flex;
            justify-content: center;
            margin-bottom: 1.5rem;
        }
        
        .date-filter .btn {
            margin: 0 0.25rem;
        }
        
        .modal-content {
            border-radius: var(--border-radius);
        }
        
        .modal-header {
            background-color: var(--primary-color);
            color: white;
            border-top-left-radius: var(--border-radius);
            border-top-right-radius: var(--border-radius);
        }
        
        .modal-title {
            font-weight: 600;
        }
        
        .btn-close {
            filter: brightness(0) invert(1);
        }
        
        .form-check-input:checked {
            background-color: var(--primary-color);
            border-color: var(--primary-color);
        }
        
        @media (max-width: 768px) {
            .header {
                padding: 1rem 0;
                margin-bottom: 1rem;
            }
            
            .card {
                margin-bottom: 1rem;
            }
            
            .summary-value {
                font-size: 1.5rem;
            }
            
            .chart-container {
                height: 250px;
            }
            
            .transaction-item {
                padding: 0.75rem;
            }
            
            .date-filter {
                flex-wrap: wrap;
            }
            
            .date-filter .btn {
                margin-bottom: 0.5rem;
            }
        }
    </style>
</head>
<body>
    <header class="header">
        <div class="container">
            <div class="row align-items-center">
                <div class="col-md-6">
                    <h1><i class="bi bi-wallet2 me-2"></i>简单记账本</h1>
                    <p class="text-muted">轻松记录每一笔收支,智能分析财务状况</p>
                </div>
                <div class="col-md-6 text-md-end mt-3 mt-md-0">
                    <button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#addTransactionModal">
                        <i class="bi bi-plus-circle me-1"></i>记一笔
                    </button>
                </div>
            </div>
        </div>
    </header>

    <div class="container">
        <div class="row">
            <div class="col-md-4">
                <div class="card summary-card">
                    <div class="card-body">
                        <h5>本月收入</h5>
                        <span class="summary-value income-value" id="totalIncome">¥0.00</span>
                    </div>
                </div>
            </div>
            <div class="col-md-4">
                <div class="card summary-card">
                    <div class="card-body">
                        <h5>本月支出</h5>
                        <span class="summary-value expense-value" id="totalExpense">¥0.00</span>
                    </div>
                </div>
            </div>
            <div class="col-md-4">
                <div class="card summary-card">
                    <div class="card-body">
                        <h5>本月结余</h5>
                        <span class="summary-value balance-value" id="totalBalance">¥0.00</span>
                    </div>
                </div>
            </div>
        </div>

        <div class="row mt-4">
            <div class="col-md-8">
                <div class="card">
                    <div class="card-header d-flex justify-content-between align-items-center">
                        <span>收支明细</span>
                        <div class="dropdown">
                            <button class="btn btn-sm btn-light dropdown-toggle" type="button" id="filterDropdown" data-bs-toggle="dropdown" aria-expanded="false">
                                筛选
                            </button>
                            <ul class="dropdown-menu" aria-labelledby="filterDropdown">
                                <li><a class="dropdown-item filter-item" href="#" data-filter="all">全部</a></li>
                                <li><a class="dropdown-item filter-item" href="#" data-filter="income">仅收入</a></li>
                                <li><a class="dropdown-item filter-item" href="#" data-filter="expense">仅支出</a></li>
                            </ul>
                        </div>
                    </div>
                    <div class="card-body">
                        <div class="date-filter">
                            <button class="btn btn-sm btn-outline-primary active" data-period="month">本月</button>
                            <button class="btn btn-sm btn-outline-primary" data-period="week">本周</button>
                            <button class="btn btn-sm btn-outline-primary" data-period="day">今天</button>
                        </div>
                        
                        <div id="transactionList">
                            <!-- 交易记录将通过JavaScript动态添加 -->
                        </div>
                        
                        <div id="emptyState" class="text-center py-5">
                            <i class="bi bi-journal-text" style="font-size: 3rem; color: #ccc;"></i>
                            <p class="mt-3 text-muted">暂无交易记录</p>
                            <button class="btn btn-primary mt-2" data-bs-toggle="modal" data-bs-target="#addTransactionModal">
                                添加第一笔记录
                            </button>
                        </div>
                    </div>
                </div>
            </div>
            
            <div class="col-md-4">
                <div class="card mb-4">
                    <div class="card-header">
                        <span>支出分类统计</span>
                    </div>
                    <div class="card-body">
                        <div class="chart-container">
                            <canvas id="expenseChart"></canvas>
                        </div>
                    </div>
                </div>
                
                <div class="card">
                    <div class="card-header">
                        <span>收入分类统计</span>
                    </div>
                    <div class="card-body">
                        <div class="chart-container">
                            <canvas id="incomeChart"></canvas>
                        </div>
                    </div>
                </div>
            </div>
        </div>
        
        <div class="row mt-4">
            <div class="col-12">
                <div class="card">
                    <div class="card-header">
                        <span>月度收支趋势</span>
                    </div>
                    <div class="card-body">
                        <div class="chart-container">
                            <canvas id="trendChart"></canvas>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
    
    <!-- 添加交易模态框 -->
    <div class="modal fade" id="addTransactionModal" tabindex="-1" aria-labelledby="addTransactionModalLabel" aria-hidden="true">
        <div class="modal-dialog">
            <div class="modal-content">
                <div class="modal-header">
                    <h5 class="modal-title" id="addTransactionModalLabel">记一笔</h5>
                    <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
                </div>
                <div class="modal-body">
                    <form id="transactionForm">
                        <div class="mb-3">
                            <label class="form-label">类型</label>
                            <div class="form-check form-check-inline">
                                <input class="form-check-input" type="radio" name="transactionType" id="incomeType" value="income" checked>
                                <label class="form-check-label" for="incomeType">收入</label>
                            </div>
                            <div class="form-check form-check-inline">
                                <input class="form-check-input" type="radio" name="transactionType" id="expenseType" value="expense">
                                <label class="form-check-label" for="expenseType">支出</label>
                            </div>
                        </div>
                        
                        <div class="mb-3">
                            <label for="amount" class="form-label">金额</label>
                            <div class="input-group">
                                <span class="input-group-text">¥</span>
                                <input type="number" class="form-control" id="amount" step="0.01" min="0" required>
                            </div>
                        </div>
                        
                        <div class="mb-3">
                            <label for="category" class="form-label">分类</label>
                            <select class="form-select" id="category" required>
                                <option value="" disabled selected>请选择分类</option>
                                <!-- 收入分类 -->
                                <optgroup label="收入" id="incomeCategories">
                                    <option value="工资">工资</option>
                                    <option value="奖金">奖金</option>
                                    <option value="投资">投资</option>
                                    <option value="兼职">兼职</option>
                                    <option value="其他收入">其他收入</option>
                                </optgroup>
                                <!-- 支出分类 -->
                                <optgroup label="支出" id="expenseCategories">
                                    <option value="餐饮">餐饮</option>
                                    <option value="购物">购物</option>
                                    <option value="交通">交通</option>
                                    <option value="住房">住房</option>
                                    <option value="娱乐">娱乐</option>
                                    <option value="医疗">医疗</option>
                                    <option value="教育">教育</option>
                                    <option value="其他支出">其他支出</option>
                                </optgroup>
                            </select>
                        </div>
                        
                        <div class="mb-3">
                            <label for="date" class="form-label">日期</label>
                            <input type="date" class="form-control" id="date" required>
                        </div>
                        
                        <div class="mb-3">
                            <label for="description" class="form-label">备注</label>
                            <textarea class="form-control" id="description" rows="2"></textarea>
                        </div>
                    </form>
                </div>
                <div class="modal-footer">
                    <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">取消</button>
                    <button type="button" class="btn btn-primary" id="saveTransactionBtn">保存</button>
                </div>
            </div>
        </div>
    </div>

    <footer class="footer">
        <div class="container">
            <div class="row">
                <div class="col-md-6">
                    <p>© 2025年8月 简单记账本</p>
                </div>
                <div class="col-md-6 text-md-end">
                    <p>科学理财,轻松生活</p>
                </div>
            </div>
        </div>
    </footer>

    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
    <script>
        document.addEventListener('DOMContentLoaded', function() {
            // 初始化日期为今天
            document.getElementById('date').valueAsDate = new Date();
            
            // 交易数据存储
            let transactions = JSON.parse(localStorage.getItem('transactions')) || [];
            
            // 更新UI
            updateUI();
            
            // 保存交易记录
            document.getElementById('saveTransactionBtn').addEventListener('click', function() {
                const form = document.getElementById('transactionForm');
                const type = document.querySelector('input[name="transactionType"]:checked').value;
                const amount = parseFloat(document.getElementById('amount').value);
                const category = document.getElementById('category').value;
                const date = document.getElementById('date').value;
                const description = document.getElementById('description').value;
                
                if (!amount || !category || !date) {
                    alert('请填写必填字段');
                    return;
                }
                
                const transaction = {
                    id: Date.now(),
                    type,
                    amount,
                    category,
                    date,
                    description,
                    timestamp: new Date().toISOString()
                };
                
                transactions.push(transaction);
                localStorage.setItem('transactions', JSON.stringify(transactions));
                
                // 重置表单
                form.reset();
                document.getElementById('date').valueAsDate = new Date();
                
                // 关闭模态框
                const modal = bootstrap.Modal.getInstance(document.getElementById('addTransactionModal'));
                modal.hide();
                
                // 更新UI
                updateUI();
            });
            
            // 类型切换时更新分类选项
            document.querySelectorAll('input[name="transactionType"]').forEach(radio => {
                radio.addEventListener('change', function() {
                    const categorySelect = document.getElementById('category');
                    categorySelect.value = '';
                    
                    if (this.value === 'income') {
                        document.getElementById('incomeCategories').style.display = 'block';
                        document.getElementById('expenseCategories').style.display = 'none';
                    } else {
                        document.getElementById('incomeCategories').style.display = 'none';
                        document.getElementById('expenseCategories').style.display = 'block';
                    }
                });
            });
            
            // 筛选功能
            document.querySelectorAll('.filter-item').forEach(item => {
                item.addEventListener('click', function(e) {
                    e.preventDefault();
                    const filter = this.getAttribute('data-filter');
                    filterTransactions(filter);
                    document.getElementById('filterDropdown').textContent = this.textContent;
                });
            });
            
            // 日期筛选
            document.querySelectorAll('.date-filter .btn').forEach(btn => {
                btn.addEventListener('click', function() {
                    document.querySelectorAll('.date-filter .btn').forEach(b => b.classList.remove('active'));
                    this.classList.add('active');
                    const period = this.getAttribute('data-period');
                    filterByDate(period);
                });
            });
            
            // 删除交易记录
            document.addEventListener('click', function(e) {
                if (e.target && e.target.classList.contains('delete-btn')) {
                    const id = parseInt(e.target.getAttribute('data-id'));
                    if (confirm('确定要删除这条记录吗?')) {
                        transactions = transactions.filter(t => t.id !== id);
                        localStorage.setItem('transactions', JSON.stringify(transactions));
                        updateUI();
                    }
                }
            });
            
            // 更新UI函数
            function updateUI() {
                updateTransactionList(transactions);
                updateSummary(transactions);
                updateCharts(transactions);
                toggleEmptyState();
            }
            
            // 更新交易列表
            function updateTransactionList(data) {
                const transactionList = document.getElementById('transactionList');
                transactionList.innerHTML = '';
                
                // 按日期降序排序
                data.sort((a, b) => new Date(b.date) - new Date(a.date));
                
                data.forEach(transaction => {
                    const item = document.createElement('div');
                    item.className = `transaction-item ${transaction.type}`;
                    
                    const formattedDate = formatDate(transaction.date);
                    const formattedAmount = formatCurrency(transaction.amount);
                    
                    item.innerHTML = `
                        <div class="d-flex justify-content-between align-items-center">
                            <div>
                                <div class="fw-bold">${transaction.category}</div>
                                <div class="text-muted small">${formattedDate} · ${transaction.description || '无备注'}</div>
                            </div>
                            <div class="d-flex align-items-center">
                                <span class="amount me-3">${transaction.type === 'income' ? '+' : '-'}${formattedAmount}</span>
                                <button class="btn btn-sm btn-outline-danger delete-btn" data-id="${transaction.id}">
                                    <i class="bi bi-trash"></i>
                                </button>
                            </div>
                        </div>
                    `;
                    
                    transactionList.appendChild(item);
                });
            }
            
            // 更新汇总信息
            function updateSummary(data) {
                const now = new Date();
                const currentMonth = now.getMonth();
                const currentYear = now.getFullYear();
                
                // 筛选本月数据
                const monthData = data.filter(t => {
                    const date = new Date(t.date);
                    return date.getMonth() === currentMonth && date.getFullYear() === currentYear;
                });
                
                const income = monthData
                    .filter(t => t.type === 'income')
                    .reduce((sum, t) => sum + t.amount, 0);
                
                const expense = monthData
                    .filter(t => t.type === 'expense')
                    .reduce((sum, t) => sum + t.amount, 0);
                
                const balance = income - expense;
                
                document.getElementById('totalIncome').textContent = formatCurrency(income);
                document.getElementById('totalExpense').textContent = formatCurrency(expense);
                document.getElementById('totalBalance').textContent = formatCurrency(balance);
                
                // 设置余额颜色
                const balanceElement = document.getElementById('totalBalance');
                if (balance > 0) {
                    balanceElement.className = 'summary-value balance-value';
                } else if (balance < 0) {
                    balanceElement.className = 'summary-value expense-value';
                } else {
                    balanceElement.className = 'summary-value';
                }
            }
            
            // 更新图表
            function updateCharts(data) {
                updateCategoryChart(data, 'expense', 'expenseChart');
                updateCategoryChart(data, 'income', 'incomeChart');
                updateTrendChart(data);
            }
            
            // 更新分类饼图
            function updateCategoryChart(data, type, chartId) {
                const ctx = document.getElementById(chartId).getContext('2d');
                
                // 筛选指定类型的交易
                const filteredData = data.filter(t => t.type === type);
                
                // 按分类汇总
                const categoryData = {};
                filteredData.forEach(t => {
                    if (categoryData[t.category]) {
                        categoryData[t.category] += t.amount;
                    } else {
                        categoryData[t.category] = t.amount;
                    }
                });
                
                // 准备图表数据
                const labels = Object.keys(categoryData);
                const values = Object.values(categoryData);
                
                // 颜色配置
                const colors = [
                    '#4CAF50', '#2196F3', '#FF9800', '#E91E63', 
                    '#9C27B0', '#00BCD4', '#FFEB3B', '#795548'
                ];
                
                // 销毁旧图表
                if (window[chartId]) {
                    window[chartId].destroy();
                }
                
                // 创建新图表
                window[chartId] = new Chart(ctx, {
                    type: 'doughnut',
                    data: {
                        labels: labels,
                        datasets: [{
                            data: values,
                            backgroundColor: colors.slice(0, labels.length),
                            borderWidth: 1
                        }]
                    },
                    options: {
                        responsive: true,
                        maintainAspectRatio: false,
                        plugins: {
                            legend: {
                                position: 'bottom',
                                labels: {
                                    boxWidth: 12,
                                    font: {
                                        size: 11
                                    }
                                }
                            }
                        }
                    }
                });
                
                // 如果没有数据,显示无数据提示
                if (labels.length === 0) {
                    ctx.font = '14px Arial';
                    ctx.textAlign = 'center';
                    ctx.fillText('暂无数据', ctx.canvas.width / 2, ctx.canvas.height / 2);
                }
            }
            
            // 更新趋势图
            function updateTrendChart(data) {
                const ctx = document.getElementById('trendChart').getContext('2d');
                
                // 获取最近6个月的数据
                const months = [];
                const incomeData = [];
                const expenseData = [];
                
                const now = new Date();
                for (let i = 5; i >= 0; i--) {
                    const month = new Date(now.getFullYear(), now.getMonth() - i, 1);
                    const monthName = month.toLocaleDateString('zh-CN', { month: 'short' });
                    months.push(monthName);
                    
                    const monthYear = month.getFullYear();
                    const monthMonth = month.getMonth();
                    
                    // 筛选当月数据
                    const monthlyData = data.filter(t => {
                        const date = new Date(t.date);
                        return date.getMonth() === monthMonth && date.getFullYear() === monthYear;
                    });
                    
                    // 计算当月收入和支出
                    const monthlyIncome = monthlyData
                        .filter(t => t.type === 'income')
                        .reduce((sum, t) => sum + t.amount, 0);
                    
                    const monthlyExpense = monthlyData
                        .filter(t => t.type === 'expense')
                        .reduce((sum, t) => sum + t.amount, 0);
                    
                    incomeData.push(monthlyIncome);
                    expenseData.push(monthlyExpense);
                }
                
                // 销毁旧图表
                if (window.trendChart) {
                    window.trendChart.destroy();
                }
                
                // 创建新图表
                window.trendChart = new Chart(ctx, {
                    type: 'line',
                    data: {
                        labels: months,
                        datasets: [
                            {
                                label: '收入',
                                data: incomeData,
                                borderColor: '#28a745',
                                backgroundColor: 'rgba(40, 167, 69, 0.1)',
                                borderWidth: 2,
                                fill: true,
                                tension: 0.4
                            },
                            {
                                label: '支出',
                                data: expenseData,
                                borderColor: '#dc3545',
                                backgroundColor: 'rgba(220, 53, 69, 0.1)',
                                borderWidth: 2,
                                fill: true,
                                tension: 0.4
                            }
                        ]
                    },
                    options: {
                        responsive: true,
                        maintainAspectRatio: false,
                        plugins: {
                            legend: {
                                position: 'top',
                            }
                        },
                        scales: {
                            y: {
                                beginAtZero: true,
                                ticks: {
                                    callback: function(value) {
                                        return '¥' + value;
                                    }
                                }
                            }
                        }
                    }
                });
            }
            
            // 筛选交易记录
            function filterTransactions(filter) {
                let filteredData;
                
                if (filter === 'all') {
                    filteredData = transactions;
                } else {
                    filteredData = transactions.filter(t => t.type === filter);
                }
                
                updateTransactionList(filteredData);
                toggleEmptyState(filteredData);
            }
            
            // 按日期筛选
            function filterByDate(period) {
                const now = new Date();
                let filteredData;
                
                switch (period) {
                    case 'day':
                        const today = now.toISOString().split('T')[0];
                        filteredData = transactions.filter(t => t.date === today);
                        break;
                    case 'week':
                        const weekStart = new Date(now);
                        weekStart.setDate(now.getDate() - now.getDay());
                        filteredData = transactions.filter(t => {
                            const date = new Date(t.date);
                            return date >= weekStart;
                        });
                        break;
                    case 'month':
                        const currentMonth = now.getMonth();
                        const currentYear = now.getFullYear();
                        filteredData = transactions.filter(t => {
                            const date = new Date(t.date);
                            return date.getMonth() === currentMonth && date.getFullYear() === currentYear;
                        });
                        break;
                    default:
                        filteredData = transactions;
                }
                
                updateTransactionList(filteredData);
                toggleEmptyState(filteredData);
            }
            
            // 切换空状态显示
            function toggleEmptyState(data = transactions) {
                const emptyState = document.getElementById('emptyState');
                if (data.length === 0) {
                    emptyState.style.display = 'block';
                } else {
                    emptyState.style.display = 'none';
                }
            }
            
            // 格式化日期
            function formatDate(dateString) {
                const date = new Date(dateString);
                return date.toLocaleDateString('zh-CN', { year: 'numeric', month: 'long', day: 'numeric' });
            }
            
            // 格式化货币
            function formatCurrency(amount) {
                return amount.toFixed(2).replace(/\d(?=(\d{3})+\.)/g, '$&,');
            }
            
            // 初始化分类显示
            if (document.querySelector('input[name="transactionType"]:checked').value === 'income') {
                document.getElementById('incomeCategories').style.display = 'block';
                document.getElementById('expenseCategories').style.display = 'none';
            } else {
                document.getElementById('incomeCategories').style.display = 'none';
                document.getElementById('expenseCategories').style.display = 'block';
            }
            
            // 添加示例数据(仅在首次加载且没有数据时)
            if (transactions.length === 0) {
                addSampleData();
            }
            
            // 添加示例数据
            function addSampleData() {
                const now = new Date();
                const today = now.toISOString().split('T')[0];
                const yesterday = new Date(now);
                yesterday.setDate(now.getDate() - 1);
                const yesterdayStr = yesterday.toISOString().split('T')[0];
                const lastWeek = new Date(now);
                lastWeek.setDate(now.getDate() - 7);
                const lastWeekStr = lastWeek.toISOString().split('T')[0];
                
                const sampleData = [
                    {
                        id: Date.now() - 1000,
                        type: 'income',
                        amount: 8000,
                        category: '工资',
                        date: lastWeekStr,
                        description: '本月工资',
                        timestamp: new Date().toISOString()
                    },
                    {
                        id: Date.now() - 2000,
                        type: 'expense',
                        amount: 1200,
                        category: '住房',
                        date: yesterdayStr,
                        description: '房租',
                        timestamp: new Date().toISOString()
                    },
                    {
                        id: Date.now() - 3000,
                        type: 'expense',
                        amount: 150,
                        category: '餐饮',
                        date: today,
                        description: '午餐',
                        timestamp: new Date().toISOString()
                    },
                    {
                        id: Date.now() - 4000,
                        type: 'expense',
                        amount: 200,
                        category: '交通',
                        date: today,
                        description: '打车',
                        timestamp: new Date().toISOString()
                    },
                    {
                        id: Date.now() - 5000,
                        type: 'income',
                        amount: 500,
                        category: '兼职',
                        date: yesterday,
                        description: '周末兼职',
                        timestamp: new Date().toISOString()
                    }
                ];
                
                transactions = sampleData;
                localStorage.setItem('transactions', JSON.stringify(transactions));
            }
        });
    </script>
</body>
</html>

效果截图

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-12-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 简单记账本功能说明
    • 系统概述
    • 核心功能
      • 1. 收支记录管理
      • 2. 交易记录查看
      • 3. 财务统计分析
      • 4. 数据可视化
      • 5. 本地数据存储
    • 使用方法
      • 记录新交易
      • 查看和筛选交易
      • 分析财务状况
    • 技术特点
    • 数据安全
    • 系统要求
    • 核心代码
    • 效果截图
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档