feat: 个人记账与预算管理系统 MVP 初始版本
This commit is contained in:
@@ -0,0 +1,609 @@
|
||||
<!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="./css/style.css">
|
||||
<!-- 引入Google Fonts - Inter -->
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
/* ========================================
|
||||
预算页面专用样式
|
||||
======================================== */
|
||||
|
||||
/* 顶部操作栏 */
|
||||
.page-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: var(--space-6);
|
||||
}
|
||||
|
||||
.page-header-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-4);
|
||||
}
|
||||
|
||||
.page-title {
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
/* 概览卡片 */
|
||||
.overview-card {
|
||||
background: var(--surface);
|
||||
border-radius: var(--radius-lg);
|
||||
padding: var(--space-6);
|
||||
box-shadow: var(--shadow-sm);
|
||||
margin-bottom: var(--space-6);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-8);
|
||||
}
|
||||
|
||||
.progress-ring-container {
|
||||
position: relative;
|
||||
width: 160px;
|
||||
height: 160px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.progress-ring {
|
||||
transform: rotate(-90deg);
|
||||
}
|
||||
|
||||
.progress-ring-bg {
|
||||
fill: none;
|
||||
stroke: var(--border);
|
||||
stroke-width: 12;
|
||||
}
|
||||
|
||||
.progress-ring-fill {
|
||||
fill: none;
|
||||
stroke: var(--primary);
|
||||
stroke-width: 12;
|
||||
stroke-linecap: round;
|
||||
stroke-dasharray: 408;
|
||||
stroke-dashoffset: 147;
|
||||
}
|
||||
|
||||
.progress-ring-text {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.progress-ring-percentage {
|
||||
font-size: 30px;
|
||||
font-weight: 700;
|
||||
color: var(--text-primary);
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.progress-ring-label {
|
||||
font-size: 12px;
|
||||
color: var(--text-secondary);
|
||||
margin-top: var(--space-1);
|
||||
}
|
||||
|
||||
.overview-info {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.overview-info-title {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: var(--text-primary);
|
||||
margin-bottom: var(--space-4);
|
||||
}
|
||||
|
||||
.overview-stats {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: var(--space-6);
|
||||
}
|
||||
|
||||
.overview-stat {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-1);
|
||||
}
|
||||
|
||||
.overview-stat-label {
|
||||
font-size: 12px;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.overview-stat-value {
|
||||
font-size: 24px;
|
||||
font-weight: 700;
|
||||
font-feature-settings: 'tnum';
|
||||
}
|
||||
|
||||
.overview-stat-value.used { color: var(--danger); }
|
||||
.overview-stat-value.remaining { color: var(--success); }
|
||||
|
||||
/* 预算列表 */
|
||||
.section-title {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: var(--text-secondary);
|
||||
margin-bottom: var(--space-4);
|
||||
padding-left: var(--space-3);
|
||||
border-left: 3px solid var(--primary);
|
||||
}
|
||||
|
||||
.budget-list {
|
||||
background: var(--surface);
|
||||
border-radius: var(--radius-lg);
|
||||
box-shadow: var(--shadow-sm);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.budget-item {
|
||||
padding: var(--space-4) var(--space-5);
|
||||
border-bottom: 1px solid var(--border);
|
||||
}
|
||||
|
||||
.budget-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.budget-item:hover {
|
||||
background: #fafafa;
|
||||
}
|
||||
|
||||
.budget-item-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: var(--space-3);
|
||||
}
|
||||
|
||||
.budget-item-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-3);
|
||||
}
|
||||
|
||||
.budget-category-icon {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: var(--radius-md);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.budget-category-name {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.budget-amounts {
|
||||
font-size: 14px;
|
||||
color: var(--text-secondary);
|
||||
margin-top: var(--space-1);
|
||||
}
|
||||
|
||||
.btn-ghost {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: var(--space-2);
|
||||
padding: 8px 16px;
|
||||
background: transparent;
|
||||
color: var(--primary);
|
||||
border: none;
|
||||
border-radius: var(--radius-md);
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.15s ease;
|
||||
}
|
||||
|
||||
.btn-ghost:hover {
|
||||
background: var(--primary-light);
|
||||
}
|
||||
|
||||
/* Primary 按钮 - 设置预算按钮 */
|
||||
.btn-primary {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 6px;
|
||||
padding: 8px 18px;
|
||||
min-height: 40px;
|
||||
background: var(--primary);
|
||||
color: #ffffff;
|
||||
border: none;
|
||||
border-radius: var(--radius-md);
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
line-height: 1.4;
|
||||
white-space: nowrap;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
background: var(--primary-hover);
|
||||
}
|
||||
|
||||
.btn-primary svg {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.budget-progress {
|
||||
margin-bottom: var(--space-2);
|
||||
}
|
||||
|
||||
.budget-progress-bar {
|
||||
height: 8px;
|
||||
background: var(--border);
|
||||
border-radius: var(--radius-sm);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.budget-progress-fill {
|
||||
height: 100%;
|
||||
border-radius: var(--radius-sm);
|
||||
transition: width 0.3s ease;
|
||||
}
|
||||
|
||||
.budget-progress-fill.normal { background: var(--success); }
|
||||
.budget-progress-fill.warning { background: var(--warning); }
|
||||
.budget-progress-fill.danger { background: var(--danger); }
|
||||
|
||||
.budget-item-footer {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.budget-percentage { font-size: 12px; font-weight: 600; }
|
||||
.budget-percentage.normal { color: var(--success); }
|
||||
.budget-percentage.warning { color: var(--warning); }
|
||||
.budget-percentage.danger { color: var(--danger); }
|
||||
|
||||
.budget-remaining { font-size: 12px; color: var(--text-secondary); }
|
||||
.budget-remaining.overdue { color: var(--danger); font-weight: 500; }
|
||||
|
||||
.warning-tag {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: var(--space-1);
|
||||
padding: 4px 8px;
|
||||
background: rgba(255, 179, 0, 0.15);
|
||||
color: var(--warning);
|
||||
border-radius: var(--radius-sm);
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* 响应式 */
|
||||
@media (max-width: 767px) {
|
||||
.overview-card {
|
||||
flex-direction: column;
|
||||
padding: var(--space-5);
|
||||
gap: var(--space-5);
|
||||
}
|
||||
.progress-ring-container {
|
||||
width: 140px;
|
||||
height: 140px;
|
||||
}
|
||||
.overview-stats {
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: var(--space-4);
|
||||
width: 100%;
|
||||
}
|
||||
.overview-stat-value { font-size: 20px; }
|
||||
.budget-item { padding: var(--space-4); }
|
||||
.page-title { font-size: 18px; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- 主布局容器 -->
|
||||
<div class="app-layout">
|
||||
<!-- 桌面端侧边栏 -->
|
||||
<aside class="sidebar" role="navigation" aria-label="侧边导航">
|
||||
<div class="sidebar-logo">
|
||||
<div class="sidebar-logo-content">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="24" height="24">
|
||||
<path d="M21 12V7H5a2 2 0 0 1 0-4h14v4"/>
|
||||
<path d="M3 5v14a2 2 0 0 0 2 2h16v-5"/>
|
||||
<path d="M18 12a2 2 0 0 0 0 4h4v-4h-4z"/>
|
||||
</svg>
|
||||
<span>个人记账</span>
|
||||
</div>
|
||||
<!-- 折叠按钮 -->
|
||||
<div class="sidebar-toggle-wrapper" data-tooltip="收起侧边栏">
|
||||
<button class="sidebar-toggle" type="button" aria-label="折叠/展开侧边栏">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<polyline points="15 18 9 12 15 6"/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<nav class="sidebar-nav">
|
||||
<a href="index.html" class="sidebar-nav-item">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/>
|
||||
<polyline points="9 22 9 12 15 12 15 22"/>
|
||||
</svg>
|
||||
<span>首页</span>
|
||||
</a>
|
||||
<a href="record.html" class="sidebar-nav-item">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<path d="M12 2v20M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6"/>
|
||||
</svg>
|
||||
<span>记账</span>
|
||||
</a>
|
||||
<a href="budget.html" class="sidebar-nav-item active" aria-current="page">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<rect x="2" y="3" width="20" height="14" rx="2" ry="2"/>
|
||||
<line x1="8" y1="21" x2="16" y2="21"/>
|
||||
<line x1="12" y1="17" x2="12" y2="21"/>
|
||||
</svg>
|
||||
<span>预算</span>
|
||||
</a>
|
||||
<a href="statistics.html" class="sidebar-nav-item">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<line x1="18" y1="20" x2="18" y2="10"/>
|
||||
<line x1="12" y1="20" x2="12" y2="4"/>
|
||||
<line x1="6" y1="20" x2="6" y2="14"/>
|
||||
</svg>
|
||||
<span>统计</span>
|
||||
</a>
|
||||
</nav>
|
||||
</aside>
|
||||
|
||||
<!-- 主内容区 -->
|
||||
<main class="main-content">
|
||||
<!-- 顶部操作栏 -->
|
||||
<header class="page-header">
|
||||
<div class="page-header-left">
|
||||
<button class="back-btn" aria-label="返回">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M15 19l-7-7 7-7" />
|
||||
</svg>
|
||||
</button>
|
||||
<h1 class="page-title">预算管理</h1>
|
||||
</div>
|
||||
<button class="btn-primary">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M12 4v16m8-8H4" />
|
||||
</svg>
|
||||
<span>设置预算</span>
|
||||
</button>
|
||||
</header>
|
||||
|
||||
<!-- 总体概览卡片 -->
|
||||
<section class="overview-card">
|
||||
<!-- 环形进度图 - SVG实现 -->
|
||||
<div class="progress-ring-container">
|
||||
<svg class="progress-ring" width="160" height="160">
|
||||
<circle
|
||||
class="progress-ring-bg"
|
||||
cx="80"
|
||||
cy="80"
|
||||
r="65"
|
||||
/>
|
||||
<circle
|
||||
class="progress-ring-fill"
|
||||
cx="80"
|
||||
cy="80"
|
||||
r="65"
|
||||
/>
|
||||
</svg>
|
||||
<div class="progress-ring-text">
|
||||
<div class="progress-ring-percentage">64%</div>
|
||||
<div class="progress-ring-label">已使用</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 概览信息 -->
|
||||
<div class="overview-info">
|
||||
<h2 class="overview-info-title">本月总预算</h2>
|
||||
<div class="overview-stats">
|
||||
<div class="overview-stat">
|
||||
<span class="overview-stat-label">总预算</span>
|
||||
<span class="overview-stat-value total">¥5,000</span>
|
||||
</div>
|
||||
<div class="overview-stat">
|
||||
<span class="overview-stat-label">已用</span>
|
||||
<span class="overview-stat-value used">¥3,200</span>
|
||||
</div>
|
||||
<div class="overview-stat">
|
||||
<span class="overview-stat-label">剩余</span>
|
||||
<span class="overview-stat-value remaining">¥1,800</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 类别预算列表 -->
|
||||
<h3 class="section-title">类别预算</h3>
|
||||
<div class="budget-list">
|
||||
<!-- 餐饮 - 70% 正常 -->
|
||||
<article class="budget-item">
|
||||
<div class="budget-item-header">
|
||||
<div class="budget-item-left">
|
||||
<div class="budget-category-icon" style="background: rgba(255, 179, 0, 0.15);">
|
||||
<!-- 餐饮图标 -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.747 0 3.332.477 4.5 1.253v13C19.832 18.477 18.247 18 16.5 18c-1.746 0-3.332.477-4.5 1.253" />
|
||||
</svg>
|
||||
</div>
|
||||
<span class="budget-category-name">餐饮</span>
|
||||
</div>
|
||||
<button class="btn-ghost" aria-label="编辑餐饮预算">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" />
|
||||
</svg>
|
||||
<span>编辑</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="budget-amounts">¥1,050 / ¥1,500</div>
|
||||
<div class="budget-progress">
|
||||
<div class="budget-progress-bar">
|
||||
<div class="budget-progress-fill normal" style="width: 70%;"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="budget-item-footer">
|
||||
<span class="budget-percentage normal">70%</span>
|
||||
<span class="budget-remaining">剩余 ¥450</span>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<!-- 交通 - 45% 正常 -->
|
||||
<article class="budget-item">
|
||||
<div class="budget-item-header">
|
||||
<div class="budget-item-left">
|
||||
<div class="budget-category-icon" style="background: rgba(0, 184, 212, 0.15);">
|
||||
<!-- 交通图标 -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M8 7h8m-8 4h8m-6 4h4M4 7h.01M4 15h16a1 1 0 001-1V8a1 1 0 00-1-1H4a1 1 0 00-1 1v6a1 1 0 001 1z" />
|
||||
</svg>
|
||||
</div>
|
||||
<span class="budget-category-name">交通</span>
|
||||
</div>
|
||||
<button class="btn-ghost" aria-label="编辑交通预算">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" />
|
||||
</svg>
|
||||
<span>编辑</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="budget-amounts">¥225 / ¥500</div>
|
||||
<div class="budget-progress">
|
||||
<div class="budget-progress-bar">
|
||||
<div class="budget-progress-fill normal" style="width: 45%;"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="budget-item-footer">
|
||||
<span class="budget-percentage normal">45%</span>
|
||||
<span class="budget-remaining">剩余 ¥275</span>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<!-- 购物 - 25% 正常 -->
|
||||
<article class="budget-item">
|
||||
<div class="budget-item-header">
|
||||
<div class="budget-item-left">
|
||||
<div class="budget-category-icon" style="background: rgba(156, 39, 176, 0.15);">
|
||||
<!-- 购物图标 -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M16 11V7a4 4 0 00-8 0v4M5 9h14l1 12H4L5 9z" />
|
||||
</svg>
|
||||
</div>
|
||||
<span class="budget-category-name">购物</span>
|
||||
</div>
|
||||
<button class="btn-ghost" aria-label="编辑购物预算">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" />
|
||||
</svg>
|
||||
<span>编辑</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="budget-amounts">¥250 / ¥1,000</div>
|
||||
<div class="budget-progress">
|
||||
<div class="budget-progress-bar">
|
||||
<div class="budget-progress-fill normal" style="width: 25%;"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="budget-item-footer">
|
||||
<span class="budget-percentage normal">25%</span>
|
||||
<span class="budget-remaining">剩余 ¥750</span>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<!-- 娱乐 - 104% 超支 -->
|
||||
<article class="budget-item">
|
||||
<div class="budget-item-header">
|
||||
<div class="budget-item-left">
|
||||
<div class="budget-category-icon" style="background: rgba(233, 30, 99, 0.15);">
|
||||
<!-- 娱乐图标 -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M14.828 14.828a4 4 0 01-5.656 0M9 10h.01M15 10h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</svg>
|
||||
</div>
|
||||
<span class="budget-category-name">娱乐</span>
|
||||
<span class="warning-tag">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" />
|
||||
</svg>
|
||||
超支
|
||||
</span>
|
||||
</div>
|
||||
<button class="btn-ghost" aria-label="编辑娱乐预算">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" />
|
||||
</svg>
|
||||
<span>编辑</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="budget-amounts">¥520 / ¥500</div>
|
||||
<div class="budget-progress">
|
||||
<div class="budget-progress-bar">
|
||||
<div class="budget-progress-fill danger" style="width: 100%;"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="budget-item-footer">
|
||||
<span class="budget-percentage danger">104%</span>
|
||||
<span class="budget-remaining overdue">超支 ¥20</span>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<!-- 移动端底部Tab导航 -->
|
||||
<nav class="bottom-tab-bar" role="navigation" aria-label="底部导航">
|
||||
<a href="index.html" class="tab-item">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/>
|
||||
<polyline points="9 22 9 12 15 12 15 22"/>
|
||||
</svg>
|
||||
<span>首页</span>
|
||||
</a>
|
||||
<a href="record.html" class="tab-item">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<path d="M12 2v20M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6"/>
|
||||
</svg>
|
||||
<span>记账</span>
|
||||
</a>
|
||||
<a href="budget.html" class="tab-item active" aria-current="page">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<rect x="2" y="3" width="20" height="14" rx="2" ry="2"/>
|
||||
<line x1="8" y1="21" x2="16" y2="21"/>
|
||||
<line x1="12" y1="17" x2="12" y2="21"/>
|
||||
</svg>
|
||||
<span>预算</span>
|
||||
</a>
|
||||
<a href="statistics.html" class="tab-item">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<line x1="18" y1="20" x2="18" y2="10"/>
|
||||
<line x1="12" y1="20" x2="12" y2="4"/>
|
||||
<line x1="6" y1="20" x2="6" y2="14"/>
|
||||
</svg>
|
||||
<span>统计</span>
|
||||
</a>
|
||||
</nav>
|
||||
<!-- 侧边栏折叠功能 -->
|
||||
<script src="./js/sidebar.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,263 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="个人记账与预算管理系统 - 简洁、专业、可信赖的个人财务管理工具">
|
||||
<title>个人记账 - 首页</title>
|
||||
<!-- 引入公共样式 -->
|
||||
<link rel="stylesheet" href="./css/style.css">
|
||||
<!-- 引入Google Fonts - Inter -->
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
|
||||
</head>
|
||||
<body>
|
||||
<!-- 主布局容器 -->
|
||||
<div class="app-layout">
|
||||
<!-- 桌面端侧边栏 -->
|
||||
<aside class="sidebar" role="navigation" aria-label="侧边导航">
|
||||
<!-- Logo 区域 -->
|
||||
<div class="sidebar-logo">
|
||||
<div class="sidebar-logo-content">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="24" height="24">
|
||||
<path d="M21 12V7H5a2 2 0 0 1 0-4h14v4"/>
|
||||
<path d="M3 5v14a2 2 0 0 0 2 2h16v-5"/>
|
||||
<path d="M18 12a2 2 0 0 0 0 4h4v-4h-4z"/>
|
||||
</svg>
|
||||
<span>个人记账</span>
|
||||
</div>
|
||||
<!-- 折叠按钮 -->
|
||||
<div class="sidebar-toggle-wrapper" data-tooltip="收起侧边栏">
|
||||
<button class="sidebar-toggle" type="button" aria-label="折叠/展开侧边栏">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<polyline points="15 18 9 12 15 6"/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 导航列表 -->
|
||||
<nav class="sidebar-nav">
|
||||
<a href="index.html" class="sidebar-nav-item active" aria-current="page">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/>
|
||||
<polyline points="9 22 9 12 15 12 15 22"/>
|
||||
</svg>
|
||||
<span>首页</span>
|
||||
</a>
|
||||
<a href="record.html" class="sidebar-nav-item">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<path d="M12 2v20M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6"/>
|
||||
</svg>
|
||||
<span>记账</span>
|
||||
</a>
|
||||
<a href="budget.html" class="sidebar-nav-item">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<rect x="2" y="3" width="20" height="14" rx="2" ry="2"/>
|
||||
<line x1="8" y1="21" x2="16" y2="21"/>
|
||||
<line x1="12" y1="17" x2="12" y2="21"/>
|
||||
</svg>
|
||||
<span>预算</span>
|
||||
</a>
|
||||
<a href="statistics.html" class="sidebar-nav-item">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<line x1="18" y1="20" x2="18" y2="10"/>
|
||||
<line x1="12" y1="20" x2="12" y2="4"/>
|
||||
<line x1="6" y1="20" x2="6" y2="14"/>
|
||||
</svg>
|
||||
<span>统计</span>
|
||||
</a>
|
||||
</nav>
|
||||
</aside>
|
||||
|
||||
<!-- 主内容区 -->
|
||||
<main class="main-content" role="main">
|
||||
<!-- 余额卡片 -->
|
||||
<section class="balance-card" aria-labelledby="balance-title">
|
||||
<p class="balance-label" id="balance-title">当前余额</p>
|
||||
<p class="balance-amount" aria-label="余额 ¥12,580.00">¥ 12,580.00</p>
|
||||
<div class="balance-summary">
|
||||
<div class="balance-summary-item income">
|
||||
<span class="label">本月收入</span>
|
||||
<span class="value">+8,500</span>
|
||||
</div>
|
||||
<div class="balance-summary-item expense">
|
||||
<span class="label">本月支出</span>
|
||||
<span class="value">-3,200</span>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 快捷操作按钮 -->
|
||||
<section class="quick-actions" aria-label="快捷操作">
|
||||
<button class="btn btn-primary" type="button" aria-label="快速记账">
|
||||
<!-- 加号图标SVG -->
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
||||
<line x1="12" y1="5" x2="12" y2="19"/>
|
||||
<line x1="5" y1="12" x2="19" y2="12"/>
|
||||
</svg>
|
||||
<span>快速记账</span>
|
||||
</button>
|
||||
<button class="btn btn-danger" type="button" aria-label="记支出">
|
||||
<!-- 减号图标SVG -->
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
||||
<line x1="5" y1="12" x2="19" y2="12"/>
|
||||
</svg>
|
||||
<span>记支出</span>
|
||||
</button>
|
||||
</section>
|
||||
|
||||
<!-- 收支双卡片 -->
|
||||
<section class="stats-grid" aria-label="收支概览">
|
||||
<article class="stat-card">
|
||||
<p class="stat-label">本月收入</p>
|
||||
<p class="stat-value income" aria-label="收入 +8,500">+8,500</p>
|
||||
</article>
|
||||
<article class="stat-card">
|
||||
<p class="stat-label">本月支出</p>
|
||||
<p class="stat-value expense" aria-label="支出 -3,200">-3,200</p>
|
||||
</article>
|
||||
</section>
|
||||
|
||||
<!-- 预算进度 -->
|
||||
<section class="budget-card" aria-labelledby="budget-title">
|
||||
<h2 class="section-title" id="budget-title">预算进度</h2>
|
||||
<div class="budget-list" role="list">
|
||||
<!-- 餐饮预算 - 70% 正常 -->
|
||||
<div class="budget-progress-item" role="listitem">
|
||||
<div class="budget-progress-header">
|
||||
<div class="budget-category">
|
||||
<span class="budget-category-icon" aria-hidden="true">🍜</span>
|
||||
<span class="budget-category-name">餐饮</span>
|
||||
</div>
|
||||
<span class="budget-amounts">1,050 / 1,500</span>
|
||||
</div>
|
||||
<div class="budget-progress-bar" role="progressbar" aria-valuenow="70" aria-valuemin="0" aria-valuemax="100" aria-label="餐饮预算已使用70%">
|
||||
<div class="budget-progress-fill normal" style="width: 70%;"></div>
|
||||
</div>
|
||||
<p class="budget-percentage">70%</p>
|
||||
</div>
|
||||
<!-- 交通预算 - 45% 正常 -->
|
||||
<div class="budget-progress-item" role="listitem">
|
||||
<div class="budget-progress-header">
|
||||
<div class="budget-category">
|
||||
<span class="budget-category-icon" aria-hidden="true">🚕</span>
|
||||
<span class="budget-category-name">交通</span>
|
||||
</div>
|
||||
<span class="budget-amounts">225 / 500</span>
|
||||
</div>
|
||||
<div class="budget-progress-bar" role="progressbar" aria-valuenow="45" aria-valuemin="0" aria-valuemax="100" aria-label="交通预算已使用45%">
|
||||
<div class="budget-progress-fill normal" style="width: 45%;"></div>
|
||||
</div>
|
||||
<p class="budget-percentage">45%</p>
|
||||
</div>
|
||||
<!-- 购物预算 - 25% 正常 -->
|
||||
<div class="budget-progress-item" role="listitem">
|
||||
<div class="budget-progress-header">
|
||||
<div class="budget-category">
|
||||
<span class="budget-category-icon" aria-hidden="true">🛒</span>
|
||||
<span class="budget-category-name">购物</span>
|
||||
</div>
|
||||
<span class="budget-amounts">250 / 1,000</span>
|
||||
</div>
|
||||
<div class="budget-progress-bar" role="progressbar" aria-valuenow="25" aria-valuemin="0" aria-valuemax="100" aria-label="购物预算已使用25%">
|
||||
<div class="budget-progress-fill normal" style="width: 25%;"></div>
|
||||
</div>
|
||||
<p class="budget-percentage">25%</p>
|
||||
</div>
|
||||
<!-- 娱乐预算 - 104% 超支 -->
|
||||
<div class="budget-progress-item" role="listitem">
|
||||
<div class="budget-progress-header">
|
||||
<div class="budget-category">
|
||||
<span class="budget-category-icon" aria-hidden="true">🎮</span>
|
||||
<span class="budget-category-name">娱乐</span>
|
||||
</div>
|
||||
<span class="budget-amounts">520 / 500</span>
|
||||
</div>
|
||||
<div class="budget-progress-bar" role="progressbar" aria-valuenow="104" aria-valuemin="0" aria-valuemax="100" aria-label="娱乐预算已超支104%">
|
||||
<div class="budget-progress-fill danger" style="width: 100%;"></div>
|
||||
</div>
|
||||
<p class="budget-percentage danger">
|
||||
104%
|
||||
<span class="budget-warning-icon" aria-label="超支警告">⚠️</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 最近记录 -->
|
||||
<section class="records-card" aria-labelledby="records-title">
|
||||
<h2 class="section-title" id="records-title">最近记录</h2>
|
||||
<div class="records-list" role="list">
|
||||
<!-- 星巴克记录 -->
|
||||
<article class="record-item" role="listitem">
|
||||
<div class="record-icon" aria-hidden="true">🍜</div>
|
||||
<div class="record-content">
|
||||
<p class="record-title">餐饮</p>
|
||||
<p class="record-note">星巴克</p>
|
||||
</div>
|
||||
<div class="record-meta">
|
||||
<p class="record-amount expense" aria-label="支出 -38元">-38</p>
|
||||
<p class="record-time">今天</p>
|
||||
</div>
|
||||
</article>
|
||||
<!-- 打车记录 -->
|
||||
<article class="record-item" role="listitem">
|
||||
<div class="record-icon" aria-hidden="true">🚕</div>
|
||||
<div class="record-content">
|
||||
<p class="record-title">交通</p>
|
||||
<p class="record-note">打车</p>
|
||||
</div>
|
||||
<div class="record-meta">
|
||||
<p class="record-amount expense" aria-label="支出 -25元">-25</p>
|
||||
<p class="record-time">今天</p>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<!-- 移动端底部Tab导航 -->
|
||||
<nav class="bottom-tab-bar" role="navigation" aria-label="底部导航">
|
||||
<a href="index.html" class="tab-item active" aria-current="page">
|
||||
<!-- 首页图标SVG -->
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
||||
<path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/>
|
||||
<polyline points="9 22 9 12 15 12 15 22"/>
|
||||
</svg>
|
||||
<span>首页</span>
|
||||
</a>
|
||||
<a href="record.html" class="tab-item">
|
||||
<!-- 记账图标SVG -->
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
||||
<path d="M12 2v20M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6"/>
|
||||
</svg>
|
||||
<span>记账</span>
|
||||
</a>
|
||||
<a href="budget.html" class="tab-item">
|
||||
<!-- 预算图标SVG -->
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
||||
<rect x="2" y="3" width="20" height="14" rx="2" ry="2"/>
|
||||
<line x1="8" y1="21" x2="16" y2="21"/>
|
||||
<line x1="12" y1="17" x2="12" y2="21"/>
|
||||
</svg>
|
||||
<span>预算</span>
|
||||
</a>
|
||||
<a href="statistics.html" class="tab-item">
|
||||
<!-- 统计图标SVG -->
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
||||
<line x1="18" y1="20" x2="18" y2="10"/>
|
||||
<line x1="12" y1="20" x2="12" y2="4"/>
|
||||
<line x1="6" y1="20" x2="6" y2="14"/>
|
||||
</svg>
|
||||
<span>统计</span>
|
||||
</a>
|
||||
</nav>
|
||||
|
||||
<!-- ECharts CDN -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/echarts@5.4.3/dist/echarts.min.js"></script>
|
||||
<!-- 侧边栏折叠功能 -->
|
||||
<script src="./js/sidebar.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
Vendored
+52
@@ -0,0 +1,52 @@
|
||||
// 侧边栏折叠功能
|
||||
(function() {
|
||||
const STORAGE_KEY = 'sidebar-collapsed';
|
||||
|
||||
// 初始化
|
||||
function init() {
|
||||
const sidebar = document.querySelector('.sidebar');
|
||||
const toggleBtn = document.querySelector('.sidebar-toggle');
|
||||
const toggleWrapper = document.querySelector('.sidebar-toggle-wrapper');
|
||||
|
||||
if (!sidebar || !toggleBtn) return;
|
||||
|
||||
// 从 localStorage 恢复状态
|
||||
const isCollapsed = localStorage.getItem(STORAGE_KEY) === 'true';
|
||||
if (isCollapsed) {
|
||||
sidebar.classList.add('collapsed');
|
||||
}
|
||||
|
||||
// 更新tooltip文字
|
||||
updateTooltip(sidebar, toggleWrapper);
|
||||
|
||||
// 绑定点击事件
|
||||
toggleBtn.addEventListener('click', function() {
|
||||
sidebar.classList.toggle('collapsed');
|
||||
const collapsed = sidebar.classList.contains('collapsed');
|
||||
localStorage.setItem(STORAGE_KEY, collapsed);
|
||||
|
||||
// 更新tooltip
|
||||
updateTooltip(sidebar, toggleWrapper);
|
||||
|
||||
// 触发自定义事件
|
||||
const event = new CustomEvent('sidebarToggle', {
|
||||
detail: { collapsed: collapsed }
|
||||
});
|
||||
document.dispatchEvent(event);
|
||||
});
|
||||
}
|
||||
|
||||
// 更新tooltip文字
|
||||
function updateTooltip(sidebar, wrapper) {
|
||||
if (!wrapper) return;
|
||||
const isCollapsed = sidebar.classList.contains('collapsed');
|
||||
wrapper.setAttribute('data-tooltip', isCollapsed ? '展开侧边栏' : '收起侧边栏');
|
||||
}
|
||||
|
||||
// DOM 加载完成后初始化
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', init);
|
||||
} else {
|
||||
init();
|
||||
}
|
||||
})();
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user