1432 lines
52 KiB
HTML
1432 lines
52 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="zh-CN">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>统计报表 - 个人收支管理系统</title>
|
|
<!-- ECharts CDN -->
|
|
<script src="https://cdn.jsdelivr.net/npm/echarts@5.4.3/dist/echarts.min.js"></script>
|
|
<!-- 公共样式 -->
|
|
<link rel="stylesheet" href="./css/style.css">
|
|
<style>
|
|
/* ============================================
|
|
统计页面专用样式
|
|
============================================ */
|
|
|
|
/* 顶部操作栏 */
|
|
.page-header {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
padding: 16px 24px;
|
|
background: var(--surface);
|
|
border-radius: var(--radius-lg);
|
|
margin-bottom: 24px;
|
|
box-shadow: var(--shadow-sm);
|
|
}
|
|
|
|
.header-left {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 16px;
|
|
}
|
|
|
|
/* 返回按钮 - 桌面端显示,移动端隐藏 */
|
|
.back-btn {
|
|
width: 40px;
|
|
height: 40px;
|
|
border-radius: var(--radius-full);
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
background: transparent;
|
|
border: 1px solid var(--border);
|
|
cursor: pointer;
|
|
font-size: 18px;
|
|
color: var(--text-primary);
|
|
transition: all 0.2s ease;
|
|
}
|
|
|
|
.back-btn:hover {
|
|
background: rgba(0, 82, 255, 0.08);
|
|
border-color: var(--primary);
|
|
}
|
|
|
|
.back-btn svg {
|
|
width: 20px;
|
|
height: 20px;
|
|
}
|
|
|
|
.page-title {
|
|
font-size: 20px;
|
|
font-weight: 600;
|
|
color: var(--text-primary);
|
|
margin: 0;
|
|
}
|
|
|
|
.header-right {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 12px;
|
|
}
|
|
|
|
/* Primary按钮 - 导出按钮 #0052ff */
|
|
.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;
|
|
}
|
|
|
|
/* Ghost按钮 - 编辑按钮 */
|
|
.btn-ghost {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
gap: 6px;
|
|
padding: 8px 16px;
|
|
min-height: 40px;
|
|
background: transparent;
|
|
color: var(--primary);
|
|
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-ghost:hover {
|
|
background: rgba(0, 82, 255, 0.08);
|
|
}
|
|
|
|
.btn-ghost svg {
|
|
width: 16px;
|
|
height: 16px;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
/* 月/年切换标签 */
|
|
.period-tabs {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
background: var(--bg);
|
|
border-radius: var(--radius-md);
|
|
padding: 3px;
|
|
gap: 0;
|
|
}
|
|
|
|
.period-tab {
|
|
padding: 6px 16px;
|
|
border: none;
|
|
background: transparent;
|
|
cursor: pointer;
|
|
font-size: 14px;
|
|
color: var(--text-secondary);
|
|
border-radius: var(--radius-sm);
|
|
transition: all 0.2s ease;
|
|
font-weight: 500;
|
|
line-height: 1.4;
|
|
white-space: nowrap;
|
|
min-height: 32px;
|
|
}
|
|
|
|
.period-tab:hover {
|
|
color: var(--text-primary);
|
|
}
|
|
|
|
.period-tab.active {
|
|
background: var(--surface);
|
|
color: var(--primary);
|
|
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
|
|
font-weight: 600;
|
|
}
|
|
|
|
/* 内容区域 */
|
|
.statistics-content {
|
|
padding: 24px;
|
|
max-width: 1280px;
|
|
}
|
|
|
|
/* 图表类型切换 - 选中态: 背景#0052ff,文字白色 */
|
|
.chart-type-switch {
|
|
display: flex;
|
|
gap: 12px;
|
|
margin-bottom: 24px;
|
|
background: var(--surface);
|
|
padding: 16px;
|
|
border-radius: var(--radius-lg);
|
|
box-shadow: var(--shadow-sm);
|
|
}
|
|
|
|
.chart-type-btn {
|
|
flex: 1;
|
|
padding: 12px 16px;
|
|
border: 1.5px solid var(--border);
|
|
border-radius: var(--radius-md);
|
|
background: var(--surface);
|
|
cursor: pointer;
|
|
text-align: center;
|
|
font-weight: 500;
|
|
color: var(--text-secondary);
|
|
transition: all 0.2s ease;
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
gap: 8px;
|
|
font-size: 14px;
|
|
line-height: 1.4;
|
|
white-space: nowrap;
|
|
min-height: 44px;
|
|
}
|
|
|
|
/* 选中态:背景#0052ff,文字白色 */
|
|
.chart-type-btn.active {
|
|
background: var(--primary);
|
|
border-color: var(--primary);
|
|
color: #ffffff;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.chart-type-btn:not(.active):hover {
|
|
border-color: var(--primary);
|
|
color: var(--primary);
|
|
background: rgba(0, 82, 255, 0.04);
|
|
}
|
|
|
|
.chart-type-btn svg {
|
|
width: 18px;
|
|
height: 18px;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
/* 图表卡片 */
|
|
.chart-card {
|
|
background: var(--surface);
|
|
border-radius: var(--radius-lg);
|
|
padding: 24px;
|
|
margin-bottom: 24px;
|
|
box-shadow: var(--shadow-sm);
|
|
border: 1px solid var(--border);
|
|
}
|
|
|
|
.chart-card:hover {
|
|
box-shadow: var(--shadow-md);
|
|
}
|
|
|
|
/* 图表卡片标题 - 遵循Ant Design规范 */
|
|
.chart-card-title {
|
|
font-size: 16px;
|
|
font-weight: 600;
|
|
color: var(--text-primary);
|
|
margin: 0 0 16px 0;
|
|
padding-left: 12px;
|
|
line-height: 1.5;
|
|
position: relative;
|
|
}
|
|
|
|
/* 标题左侧装饰条 */
|
|
.chart-card-title::before {
|
|
content: '';
|
|
position: absolute;
|
|
left: 0;
|
|
top: 50%;
|
|
transform: translateY(-50%);
|
|
width: 3px;
|
|
height: 16px;
|
|
background: var(--primary);
|
|
border-radius: 2px;
|
|
}
|
|
|
|
/* ECharts容器 */
|
|
.echarts-container {
|
|
width: 100%;
|
|
height: 320px;
|
|
}
|
|
|
|
/* 饼图特殊布局 */
|
|
.pie-chart-wrapper {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0;
|
|
justify-content: center;
|
|
}
|
|
|
|
.pie-chart-container {
|
|
flex: 1;
|
|
max-width: 400px;
|
|
height: 280px;
|
|
}
|
|
|
|
.pie-legend {
|
|
width: 160px;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 16px;
|
|
margin-left: -30px;
|
|
}
|
|
|
|
.legend-item {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
font-size: 14px;
|
|
}
|
|
|
|
.legend-color {
|
|
width: 12px;
|
|
height: 12px;
|
|
border-radius: var(--radius-sm);
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.legend-label {
|
|
color: var(--text-secondary);
|
|
flex: 1;
|
|
}
|
|
|
|
.legend-value {
|
|
font-weight: 600;
|
|
color: var(--text-primary);
|
|
}
|
|
|
|
/* Toast提示 */
|
|
.toast {
|
|
position: fixed;
|
|
top: 80px;
|
|
left: 50%;
|
|
transform: translateX(-50%) translateY(-100px);
|
|
background: var(--text-primary);
|
|
color: white;
|
|
padding: var(--space-md) var(--space-lg);
|
|
border-radius: var(--radius-md);
|
|
font-size: 14px;
|
|
font-weight: 500;
|
|
z-index: 1000;
|
|
opacity: 0;
|
|
transition: all 0.3s ease;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: var(--space-sm);
|
|
}
|
|
|
|
.toast.show {
|
|
transform: translateX(-50%) translateY(0);
|
|
opacity: 1;
|
|
}
|
|
|
|
.toast svg {
|
|
width: 18px;
|
|
height: 18px;
|
|
color: var(--success);
|
|
}
|
|
|
|
/* ============================================
|
|
移动端响应式 - 底部64px Tab导航
|
|
============================================ */
|
|
@media (max-width: 768px) {
|
|
/* 隐藏桌面侧边栏 */
|
|
.sidebar {
|
|
display: none;
|
|
}
|
|
|
|
.main-content {
|
|
margin-left: 0;
|
|
}
|
|
|
|
/* 返回按钮移动端隐藏 */
|
|
.back-btn {
|
|
display: none;
|
|
}
|
|
|
|
.page-header {
|
|
padding: 12px 16px;
|
|
margin-bottom: 16px;
|
|
}
|
|
|
|
.page-title {
|
|
font-size: 18px;
|
|
}
|
|
|
|
.header-right {
|
|
gap: 8px;
|
|
flex-wrap: wrap;
|
|
}
|
|
|
|
.btn-primary span,
|
|
.btn-ghost span {
|
|
display: none;
|
|
}
|
|
|
|
.btn-primary,
|
|
.btn-ghost {
|
|
padding: 8px 10px;
|
|
min-height: 36px;
|
|
}
|
|
|
|
.period-tabs {
|
|
padding: 2px;
|
|
}
|
|
|
|
.period-tab {
|
|
padding: 6px 12px;
|
|
font-size: 13px;
|
|
}
|
|
|
|
.statistics-content {
|
|
padding: 16px;
|
|
padding-bottom: 120px;
|
|
}
|
|
|
|
.chart-card:last-child {
|
|
margin-bottom: 40px;
|
|
}
|
|
|
|
.chart-type-switch {
|
|
padding: 12px;
|
|
gap: 8px;
|
|
flex-direction: row;
|
|
}
|
|
|
|
.chart-type-btn {
|
|
padding: 10px 8px;
|
|
font-size: 13px;
|
|
min-height: 40px;
|
|
gap: 6px;
|
|
}
|
|
|
|
.chart-type-btn svg {
|
|
width: 16px;
|
|
height: 16px;
|
|
}
|
|
|
|
.chart-card {
|
|
padding: 16px;
|
|
margin-bottom: 16px;
|
|
}
|
|
|
|
.chart-card-title {
|
|
font-size: 15px;
|
|
margin-bottom: 12px;
|
|
}
|
|
|
|
.echarts-container {
|
|
height: 260px;
|
|
}
|
|
|
|
.pie-chart-wrapper {
|
|
flex-direction: column;
|
|
gap: 16px;
|
|
}
|
|
|
|
.pie-legend {
|
|
width: 100%;
|
|
flex-direction: row;
|
|
flex-wrap: wrap;
|
|
justify-content: center;
|
|
gap: 8px 16px;
|
|
}
|
|
|
|
.legend-item {
|
|
font-size: 12px;
|
|
}
|
|
}
|
|
|
|
/* 平板适配 */
|
|
@media (min-width: 769px) and (max-width: 1023px) {
|
|
.sidebar {
|
|
width: 200px;
|
|
}
|
|
|
|
.main-content {
|
|
margin-left: 200px;
|
|
}
|
|
}
|
|
|
|
/* ============================================
|
|
底部Tab导航 - 移动端显示
|
|
============================================ */
|
|
.bottom-tab-bar {
|
|
position: fixed;
|
|
bottom: 0;
|
|
left: 0;
|
|
right: 0;
|
|
height: 64px;
|
|
background: var(--surface);
|
|
border-top: 1px solid var(--border);
|
|
display: flex;
|
|
justify-content: space-around;
|
|
align-items: center;
|
|
padding: 0;
|
|
z-index: 100;
|
|
}
|
|
|
|
.tab-item {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
justify-content: center;
|
|
gap: 2px;
|
|
flex: 1;
|
|
height: 100%;
|
|
color: var(--text-secondary);
|
|
text-decoration: none;
|
|
font-size: 12px;
|
|
cursor: pointer;
|
|
transition: color 0.2s ease;
|
|
}
|
|
|
|
.tab-item svg {
|
|
width: 24px;
|
|
height: 24px;
|
|
}
|
|
|
|
.tab-item.active {
|
|
color: var(--primary);
|
|
}
|
|
|
|
.tab-item.active svg {
|
|
color: var(--primary);
|
|
}
|
|
|
|
/* 桌面端隐藏底部导航 */
|
|
@media (min-width: 769px) {
|
|
.bottom-tab-bar {
|
|
display: none;
|
|
}
|
|
|
|
.statistics-content {
|
|
padding-bottom: var(--space-lg);
|
|
}
|
|
}
|
|
|
|
/* 页面缩放自适应 - 支持150%和200% */
|
|
@media (min-width: 1400px) {
|
|
.statistics-content {
|
|
max-width: 1100px;
|
|
}
|
|
}
|
|
|
|
@media (min-width: 1600px) {
|
|
.statistics-content {
|
|
max-width: 1000px;
|
|
}
|
|
}
|
|
</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" aria-label="首页">
|
|
<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" aria-label="记账">
|
|
<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" aria-label="预算">
|
|
<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 active" aria-current="page" aria-label="统计">
|
|
<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="header-left">
|
|
<button class="back-btn" onclick="history.back()" aria-label="返回上一页">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<path d="M19 12H5M12 19l-7-7 7-7"/>
|
|
</svg>
|
|
</button>
|
|
<h1 class="page-title">统计报表</h1>
|
|
</div>
|
|
<div class="header-right">
|
|
<!-- Primary按钮 - 导出按钮 #0052ff -->
|
|
<button class="btn-primary" id="exportBtn" aria-label="导出报表">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/>
|
|
<polyline points="7 10 12 15 17 10"/>
|
|
<line x1="12" y1="15" x2="12" y2="3"/>
|
|
</svg>
|
|
<span>导出</span>
|
|
</button>
|
|
<div class="period-tabs">
|
|
<button class="period-tab active" data-period="month">月</button>
|
|
<button class="period-tab" data-period="year">年</button>
|
|
</div>
|
|
</div>
|
|
</header>
|
|
|
|
<!-- 统计内容区域 -->
|
|
<div class="statistics-content">
|
|
<!-- 图表类型切换 - 选中态: 背景#0052ff,文字白色 -->
|
|
<div class="chart-type-switch" role="tablist" aria-label="图表类型">
|
|
<button class="chart-type-btn active" data-type="line" role="tab" aria-selected="true" aria-label="折线图">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<path d="M3 3v18h18"/>
|
|
<path d="M18 9l-5 5-4-4-3 3"/>
|
|
</svg>
|
|
折线图
|
|
</button>
|
|
<button class="chart-type-btn" data-type="bar" role="tab" aria-selected="false" aria-label="柱状图">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<rect x="3" y="12" width="4" height="9"/>
|
|
<rect x="10" y="8" width="4" height="13"/>
|
|
<rect x="17" y="4" width="4" height="17"/>
|
|
</svg>
|
|
柱状图
|
|
</button>
|
|
<button class="chart-type-btn" data-type="pie" role="tab" aria-selected="false" aria-label="饼图">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<path d="M21.21 15.89A10 10 0 1 1 8 2.83"/>
|
|
<path d="M22 12A10 10 0 0 0 12 2v10z"/>
|
|
</svg>
|
|
饼图
|
|
</button>
|
|
</div>
|
|
|
|
<!-- 月度收支趋势图 -->
|
|
<section class="chart-card" data-visible="line,bar" aria-labelledby="trend-title">
|
|
<h2 class="chart-card-title" id="trend-title">月度收支趋势</h2>
|
|
<div id="trendChart" class="echarts-container" role="img" aria-label="月度收支趋势图表"></div>
|
|
</section>
|
|
|
|
<!-- 支出构成饼图 -->
|
|
<section class="chart-card" data-visible="pie" aria-labelledby="expense-title">
|
|
<h2 class="chart-card-title" id="expense-title">支出构成</h2>
|
|
<div class="pie-chart-wrapper">
|
|
<div id="expensePieChart" class="pie-chart-container" role="img" aria-label="支出构成饼图"></div>
|
|
<div class="pie-legend" id="pieLegend" aria-label="图例说明"></div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- 月度对比柱状图 -->
|
|
<section class="chart-card" data-visible="line,bar,pie" aria-labelledby="compare-title">
|
|
<h2 class="chart-card-title" id="compare-title">月度对比</h2>
|
|
<div id="compareChart" class="echarts-container" role="img" aria-label="月度对比图表"></div>
|
|
</section>
|
|
</div>
|
|
</main>
|
|
</div>
|
|
|
|
<!-- Toast提示 -->
|
|
<div class="toast" id="toast" role="alert" aria-live="polite">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/>
|
|
<polyline points="22 4 12 14.01 9 11.01"/>
|
|
</svg>
|
|
<span id="toastMessage">导出成功</span>
|
|
</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">
|
|
<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 active" aria-current="page">
|
|
<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>
|
|
/**
|
|
* 统计页面JavaScript
|
|
* 功能:图表渲染、交互切换、数据展示
|
|
* 遵循规范:收入色#00c853,支出色#ff3d00
|
|
*/
|
|
|
|
// 示例数据:4月1日-25日每日收支
|
|
const dailyData = {
|
|
dates: [],
|
|
income: [],
|
|
expense: []
|
|
};
|
|
|
|
// 生成4月1日-25日的数据
|
|
for (let day = 1; day <= 25; day++) {
|
|
dailyData.dates.push(`4月${day}日`);
|
|
// 收入:800-2000之间波动,整体有上升趋势
|
|
dailyData.income.push(Math.floor(800 + Math.random() * 1200 + day * 30));
|
|
// 支出:500-1500之间波动
|
|
dailyData.expense.push(Math.floor(500 + Math.random() * 1000 + day * 15));
|
|
}
|
|
|
|
// 支出类别数据 - 按照示例数据比例
|
|
// 餐饮35%、交通20%、购物25%、娱乐10%、其他10%
|
|
// 总支出:¥10,000
|
|
const expenseCategoryData = [
|
|
{ name: '餐饮', value: 3500, percentage: 35, color: '#00c853' }, // 绿色
|
|
{ name: '交通', value: 2000, percentage: 20, color: '#3B82F6' }, // 蓝色
|
|
{ name: '购物', value: 2500, percentage: 25, color: '#ff3d00' }, // 红色
|
|
{ name: '娱乐', value: 1000, percentage: 10, color: '#F59E0B' }, // 橙色
|
|
{ name: '其他', value: 1000, percentage: 10, color: '#8B5CF6' } // 紫色
|
|
];
|
|
|
|
// 月度对比数据
|
|
const compareData = {
|
|
months: ['本月', '上月'],
|
|
income: [28000, 25000],
|
|
expense: [18000, 16000],
|
|
surplus: [10000, 9000] // 盈余
|
|
};
|
|
|
|
// ECharts实例
|
|
let trendChart, expensePieChart, compareChart;
|
|
|
|
// 当前状态
|
|
let currentTrendType = 'line'; // line | bar
|
|
let currentPeriod = 'month'; // month | year
|
|
|
|
/**
|
|
* 初始化月度收支趋势图
|
|
*/
|
|
function initTrendChart() {
|
|
const chartDom = document.getElementById('trendChart');
|
|
trendChart = echarts.init(chartDom);
|
|
renderTrendChart();
|
|
}
|
|
|
|
/**
|
|
* 渲染月度收支趋势图
|
|
* 收入线:绿色 #00c853
|
|
* 支出线:红色 #ff3d00
|
|
*/
|
|
function renderTrendChart() {
|
|
let option;
|
|
|
|
if (currentTrendType === 'line') {
|
|
// 折线图配置
|
|
option = {
|
|
animation: true,
|
|
animationDuration: 1500,
|
|
animationEasing: 'cubicOut',
|
|
animationDurationUpdate: 800,
|
|
universalTransition: {
|
|
enabled: true,
|
|
seriesKey: 'trend'
|
|
},
|
|
tooltip: {
|
|
trigger: 'axis',
|
|
backgroundColor: 'rgba(26, 26, 26, 0.95)',
|
|
borderColor: 'transparent',
|
|
textStyle: { color: '#fff' },
|
|
formatter: function(params) {
|
|
let result = params[0].axisValue + '<br/>';
|
|
params.forEach(param => {
|
|
const color = param.seriesName === '收入' ? '#00c853' : '#ff3d00';
|
|
const prefix = param.seriesName === '收入' ? '+' : '-';
|
|
result += `<span style="color:${color}">●</span> ${param.seriesName}: ${prefix}¥${param.value.toLocaleString()}<br/>`;
|
|
});
|
|
return result;
|
|
},
|
|
transitionDuration: 0.3
|
|
},
|
|
legend: {
|
|
data: ['收入', '支出'],
|
|
bottom: 0,
|
|
textStyle: { color: '#737373' },
|
|
animationDurationUpdate: 300
|
|
},
|
|
grid: {
|
|
left: '3%',
|
|
right: '4%',
|
|
bottom: '15%',
|
|
top: '10%',
|
|
containLabel: true
|
|
},
|
|
xAxis: {
|
|
type: 'category',
|
|
boundaryGap: false,
|
|
data: dailyData.dates,
|
|
axisLine: { lineStyle: { color: '#e5e5e5' } },
|
|
axisLabel: {
|
|
color: '#737373',
|
|
interval: 4,
|
|
fontSize: 11
|
|
}
|
|
},
|
|
yAxis: {
|
|
type: 'value',
|
|
axisLine: { show: false },
|
|
splitLine: { lineStyle: { color: '#f5f5f5' } },
|
|
axisLabel: {
|
|
color: '#737373',
|
|
formatter: function(value) {
|
|
return '¥' + (value / 1000) + 'k';
|
|
}
|
|
}
|
|
},
|
|
series: [
|
|
{
|
|
name: '收入',
|
|
type: 'line',
|
|
smooth: true,
|
|
symbol: 'circle',
|
|
symbolSize: 6,
|
|
lineStyle: { color: '#00c853', width: 2 },
|
|
itemStyle: { color: '#00c853' },
|
|
areaStyle: {
|
|
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
|
{ offset: 0, color: 'rgba(0, 200, 83, 0.3)' },
|
|
{ offset: 1, color: 'rgba(0, 200, 83, 0.05)' }
|
|
])
|
|
},
|
|
data: dailyData.income,
|
|
valueAnimation: true,
|
|
animationDuration: 2000,
|
|
animationEasing: 'cubicOut',
|
|
animationDelay: function(idx) {
|
|
return idx * 60;
|
|
},
|
|
emphasis: {
|
|
disabled: false,
|
|
lineStyle: {
|
|
width: 4,
|
|
shadowBlur: 10,
|
|
shadowColor: 'rgba(0, 200, 83, 0.5)'
|
|
},
|
|
itemStyle: {
|
|
shadowBlur: 10,
|
|
shadowColor: 'rgba(0, 200, 83, 0.5)',
|
|
borderColor: '#fff',
|
|
borderWidth: 2
|
|
},
|
|
scale: true,
|
|
scaleSize: 12
|
|
}
|
|
},
|
|
{
|
|
name: '支出',
|
|
type: 'line',
|
|
smooth: true,
|
|
symbol: 'circle',
|
|
symbolSize: 6,
|
|
lineStyle: { color: '#ff3d00', width: 2 },
|
|
itemStyle: { color: '#ff3d00' },
|
|
areaStyle: {
|
|
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
|
{ offset: 0, color: 'rgba(255, 61, 0, 0.3)' },
|
|
{ offset: 1, color: 'rgba(255, 61, 0, 0.05)' }
|
|
])
|
|
},
|
|
data: dailyData.expense,
|
|
valueAnimation: true,
|
|
animationDuration: 2000,
|
|
animationEasing: 'cubicOut',
|
|
animationDelay: function(idx) {
|
|
return idx * 60 + 150;
|
|
},
|
|
emphasis: {
|
|
disabled: false,
|
|
lineStyle: {
|
|
width: 4,
|
|
shadowBlur: 10,
|
|
shadowColor: 'rgba(255, 61, 0, 0.5)'
|
|
},
|
|
itemStyle: {
|
|
shadowBlur: 10,
|
|
shadowColor: 'rgba(255, 61, 0, 0.5)',
|
|
borderColor: '#fff',
|
|
borderWidth: 2
|
|
},
|
|
scale: true,
|
|
scaleSize: 12
|
|
}
|
|
}
|
|
]
|
|
};
|
|
} else {
|
|
// 柱状图配置
|
|
option = {
|
|
animation: true,
|
|
animationDuration: 1200,
|
|
animationEasing: 'elasticOut',
|
|
animationDurationUpdate: 800,
|
|
universalTransition: {
|
|
enabled: true,
|
|
seriesKey: 'trend'
|
|
},
|
|
tooltip: {
|
|
trigger: 'axis',
|
|
backgroundColor: 'rgba(26, 26, 26, 0.95)',
|
|
borderColor: 'transparent',
|
|
textStyle: { color: '#fff' },
|
|
axisPointer: { type: 'shadow' },
|
|
transitionDuration: 0.3
|
|
},
|
|
legend: {
|
|
data: ['收入', '支出'],
|
|
bottom: 0,
|
|
textStyle: { color: '#737373' },
|
|
animationDurationUpdate: 300
|
|
},
|
|
grid: {
|
|
left: '3%',
|
|
right: '4%',
|
|
bottom: '15%',
|
|
top: '10%',
|
|
containLabel: true
|
|
},
|
|
xAxis: {
|
|
type: 'category',
|
|
data: dailyData.dates,
|
|
axisLine: { lineStyle: { color: '#e5e5e5' } },
|
|
axisLabel: {
|
|
color: '#737373',
|
|
interval: 4,
|
|
fontSize: 11
|
|
}
|
|
},
|
|
yAxis: {
|
|
type: 'value',
|
|
axisLine: { show: false },
|
|
splitLine: { lineStyle: { color: '#f5f5f5' } },
|
|
axisLabel: {
|
|
color: '#737373',
|
|
formatter: function(value) {
|
|
return '¥' + (value / 1000) + 'k';
|
|
}
|
|
}
|
|
},
|
|
series: [
|
|
{
|
|
name: '收入',
|
|
type: 'bar',
|
|
barWidth: '35%',
|
|
itemStyle: {
|
|
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
|
{ offset: 0, color: '#00c853' },
|
|
{ offset: 1, color: '#00a844' }
|
|
]),
|
|
borderRadius: [4, 4, 0, 0]
|
|
},
|
|
data: dailyData.income,
|
|
valueAnimation: true,
|
|
animationDuration: 1500,
|
|
animationEasing: 'cubicOut',
|
|
animationDelay: function(idx) {
|
|
return idx * 50;
|
|
},
|
|
emphasis: {
|
|
itemStyle: {
|
|
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
|
{ offset: 0, color: '#00e05c' },
|
|
{ offset: 1, color: '#00c853' }
|
|
]),
|
|
shadowBlur: 15,
|
|
shadowColor: 'rgba(0, 200, 83, 0.4)'
|
|
},
|
|
scale: true,
|
|
scaleSize: 10
|
|
}
|
|
},
|
|
{
|
|
name: '支出',
|
|
type: 'bar',
|
|
barWidth: '35%',
|
|
itemStyle: {
|
|
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
|
{ offset: 0, color: '#ff3d00' },
|
|
{ offset: 1, color: '#e63600' }
|
|
]),
|
|
borderRadius: [4, 4, 0, 0]
|
|
},
|
|
data: dailyData.expense,
|
|
valueAnimation: true,
|
|
animationDuration: 1500,
|
|
animationEasing: 'cubicOut',
|
|
animationDelay: function(idx) {
|
|
return idx * 50 + 100;
|
|
},
|
|
emphasis: {
|
|
itemStyle: {
|
|
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
|
{ offset: 0, color: '#ff5722' },
|
|
{ offset: 1, color: '#ff3d00' }
|
|
]),
|
|
shadowBlur: 15,
|
|
shadowColor: 'rgba(255, 61, 0, 0.4)'
|
|
},
|
|
scale: true,
|
|
scaleSize: 10
|
|
}
|
|
}
|
|
]
|
|
};
|
|
}
|
|
|
|
trendChart.setOption(option, true);
|
|
}
|
|
|
|
/**
|
|
* 初始化支出构成饼图
|
|
* 环形图样式,中心显示总支出金额
|
|
*/
|
|
function initExpensePieChart() {
|
|
const chartDom = document.getElementById('expensePieChart');
|
|
expensePieChart = echarts.init(chartDom);
|
|
renderExpensePieChart();
|
|
renderPieLegend();
|
|
}
|
|
|
|
/**
|
|
* 渲染支出构成饼图 - 环形图样式
|
|
*/
|
|
function renderExpensePieChart() {
|
|
const total = expenseCategoryData.reduce((sum, item) => sum + item.value, 0);
|
|
|
|
const option = {
|
|
animation: true,
|
|
animationDuration: 1000,
|
|
animationEasing: 'cubicOut',
|
|
animationDurationUpdate: 600,
|
|
tooltip: {
|
|
trigger: 'item',
|
|
backgroundColor: 'rgba(26, 26, 26, 0.95)',
|
|
borderColor: 'transparent',
|
|
textStyle: { color: '#fff' },
|
|
formatter: function(params) {
|
|
return `${params.name}: ¥${params.value.toLocaleString()}<br/>占比: ${params.percent}%`;
|
|
},
|
|
transitionDuration: 0.3
|
|
},
|
|
series: [
|
|
{
|
|
type: 'pie',
|
|
radius: ['45%', '75%'],
|
|
center: ['50%', '50%'],
|
|
avoidLabelOverlap: false,
|
|
itemStyle: {
|
|
borderRadius: 4,
|
|
borderColor: '#fff',
|
|
borderWidth: 2
|
|
},
|
|
label: {
|
|
show: true,
|
|
position: 'center',
|
|
formatter: function() {
|
|
return '总支出\n¥' + total.toLocaleString();
|
|
},
|
|
fontSize: 16,
|
|
fontWeight: 600,
|
|
color: '#1a1a1a',
|
|
lineHeight: 24
|
|
},
|
|
emphasis: {
|
|
label: {
|
|
show: true,
|
|
fontSize: 16,
|
|
fontWeight: 600
|
|
},
|
|
scale: true,
|
|
scaleSize: 8,
|
|
itemStyle: {
|
|
shadowBlur: 20,
|
|
shadowColor: 'rgba(0, 0, 0, 0.3)'
|
|
}
|
|
},
|
|
labelLine: {
|
|
show: false
|
|
},
|
|
data: expenseCategoryData.map(item => ({
|
|
value: item.value,
|
|
name: item.name,
|
|
itemStyle: { color: item.color }
|
|
})),
|
|
animationType: 'expansion',
|
|
animationDelay: function(idx) {
|
|
return idx * 150;
|
|
}
|
|
}
|
|
]
|
|
};
|
|
|
|
expensePieChart.setOption(option);
|
|
}
|
|
|
|
/**
|
|
* 渲染饼图图例
|
|
*/
|
|
function renderPieLegend() {
|
|
const legendContainer = document.getElementById('pieLegend');
|
|
|
|
legendContainer.innerHTML = expenseCategoryData.map(item => {
|
|
return `
|
|
<div class="legend-item">
|
|
<span class="legend-color" style="background-color: ${item.color}"></span>
|
|
<span class="legend-label">${item.name}</span>
|
|
<span class="legend-value">${item.percentage}%</span>
|
|
</div>
|
|
`;
|
|
}).join('');
|
|
}
|
|
|
|
/**
|
|
* 初始化月度对比柱状图
|
|
*/
|
|
function initCompareChart() {
|
|
const chartDom = document.getElementById('compareChart');
|
|
compareChart = echarts.init(chartDom);
|
|
renderCompareChart();
|
|
}
|
|
|
|
/**
|
|
* 渲染月度对比柱状图
|
|
*/
|
|
function renderCompareChart() {
|
|
const option = {
|
|
animation: true,
|
|
animationDuration: 900,
|
|
animationEasing: 'elasticOut',
|
|
animationDurationUpdate: 500,
|
|
universalTransition: {
|
|
enabled: true
|
|
},
|
|
tooltip: {
|
|
trigger: 'axis',
|
|
backgroundColor: 'rgba(26, 26, 26, 0.95)',
|
|
borderColor: 'transparent',
|
|
textStyle: { color: '#fff' },
|
|
axisPointer: { type: 'shadow' },
|
|
formatter: function(params) {
|
|
let result = params[0].axisValue + '<br/>';
|
|
params.forEach(param => {
|
|
const prefix = param.seriesName === '收入' ? '+' : (param.seriesName === '支出' ? '-' : '');
|
|
const color = param.seriesName === '收入' ? '#00c853' : (param.seriesName === '支出' ? '#ff3d00' : '#0052ff');
|
|
result += `<span style="color:${color}">●</span> ${param.seriesName}: ${prefix}¥${param.value.toLocaleString()}<br/>`;
|
|
});
|
|
return result;
|
|
},
|
|
transitionDuration: 0.3
|
|
},
|
|
legend: {
|
|
data: ['收入', '支出', '盈余'],
|
|
bottom: 0,
|
|
textStyle: { color: '#737373' },
|
|
animationDurationUpdate: 300
|
|
},
|
|
grid: {
|
|
left: '3%',
|
|
right: '4%',
|
|
bottom: '15%',
|
|
top: '10%',
|
|
containLabel: true
|
|
},
|
|
xAxis: {
|
|
type: 'category',
|
|
data: compareData.months,
|
|
axisLine: { lineStyle: { color: '#e5e5e5' } },
|
|
axisLabel: { color: '#737373', fontSize: 13 }
|
|
},
|
|
yAxis: {
|
|
type: 'value',
|
|
axisLine: { show: false },
|
|
splitLine: { lineStyle: { color: '#f5f5f5' } },
|
|
axisLabel: {
|
|
color: '#737373',
|
|
formatter: function(value) {
|
|
return '¥' + (value / 1000) + 'k';
|
|
}
|
|
}
|
|
},
|
|
series: [
|
|
{
|
|
name: '收入',
|
|
type: 'bar',
|
|
barWidth: '22%',
|
|
itemStyle: {
|
|
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
|
{ offset: 0, color: '#00c853' },
|
|
{ offset: 1, color: '#00a844' }
|
|
]),
|
|
borderRadius: [4, 4, 0, 0]
|
|
},
|
|
data: compareData.income,
|
|
animationDelay: function(idx) {
|
|
return idx * 200;
|
|
},
|
|
emphasis: {
|
|
itemStyle: {
|
|
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
|
{ offset: 0, color: '#00e05c' },
|
|
{ offset: 1, color: '#00c853' }
|
|
]),
|
|
shadowBlur: 15,
|
|
shadowColor: 'rgba(0, 200, 83, 0.4)'
|
|
},
|
|
scale: true,
|
|
scaleSize: 8
|
|
}
|
|
},
|
|
{
|
|
name: '支出',
|
|
type: 'bar',
|
|
barWidth: '22%',
|
|
itemStyle: {
|
|
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
|
{ offset: 0, color: '#ff3d00' },
|
|
{ offset: 1, color: '#e63600' }
|
|
]),
|
|
borderRadius: [4, 4, 0, 0]
|
|
},
|
|
data: compareData.expense,
|
|
animationDelay: function(idx) {
|
|
return idx * 200 + 100;
|
|
},
|
|
emphasis: {
|
|
itemStyle: {
|
|
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
|
{ offset: 0, color: '#ff5722' },
|
|
{ offset: 1, color: '#ff3d00' }
|
|
]),
|
|
shadowBlur: 15,
|
|
shadowColor: 'rgba(255, 61, 0, 0.4)'
|
|
},
|
|
scale: true,
|
|
scaleSize: 8
|
|
}
|
|
},
|
|
{
|
|
name: '盈余',
|
|
type: 'bar',
|
|
barWidth: '22%',
|
|
itemStyle: {
|
|
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
|
{ offset: 0, color: '#0052ff' },
|
|
{ offset: 1, color: '#0041cc' }
|
|
]),
|
|
borderRadius: [4, 4, 0, 0]
|
|
},
|
|
data: compareData.surplus,
|
|
animationDelay: function(idx) {
|
|
return idx * 200 + 200;
|
|
},
|
|
emphasis: {
|
|
itemStyle: {
|
|
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
|
{ offset: 0, color: '#336bff' },
|
|
{ offset: 1, color: '#0052ff' }
|
|
]),
|
|
shadowBlur: 15,
|
|
shadowColor: 'rgba(0, 82, 255, 0.4)'
|
|
},
|
|
scale: true,
|
|
scaleSize: 8
|
|
}
|
|
}
|
|
]
|
|
};
|
|
|
|
compareChart.setOption(option);
|
|
}
|
|
|
|
/**
|
|
* 显示Toast提示
|
|
* @param {string} message - 提示消息
|
|
*/
|
|
function showToast(message) {
|
|
const toast = document.getElementById('toast');
|
|
const toastMessage = document.getElementById('toastMessage');
|
|
toastMessage.textContent = message;
|
|
toast.classList.add('show');
|
|
|
|
setTimeout(() => {
|
|
toast.classList.remove('show');
|
|
}, 2500);
|
|
}
|
|
|
|
/**
|
|
* 图表类型与标题映射
|
|
*/
|
|
const chartTypeTitles = {
|
|
line: '月度收支趋势',
|
|
bar: '月度收支趋势',
|
|
pie: '支出构成'
|
|
};
|
|
|
|
/**
|
|
* 控制图表卡片显示/隐藏
|
|
* @param {string} chartType - 当前图表类型
|
|
*/
|
|
function updateChartCardVisibility(chartType) {
|
|
document.querySelectorAll('.chart-card').forEach(card => {
|
|
const visibleTypes = card.dataset.visible.split(',');
|
|
card.style.display = visibleTypes.includes(chartType) ? '' : 'none';
|
|
});
|
|
// 动态更新标题
|
|
const trendTitle = document.getElementById('trend-title');
|
|
if (trendTitle) {
|
|
trendTitle.textContent = chartTypeTitles[chartType];
|
|
}
|
|
// 切换后延迟执行 resize,确保容器尺寸正确
|
|
setTimeout(() => {
|
|
if (chartType === 'pie') {
|
|
expensePieChart && expensePieChart.resize();
|
|
expensePieChart && expensePieChart.setOption(expensePieChart.getOption());
|
|
} else {
|
|
trendChart && trendChart.resize();
|
|
compareChart && compareChart.resize();
|
|
}
|
|
}, 100);
|
|
}
|
|
|
|
/**
|
|
* 绑定事件监听
|
|
*/
|
|
function bindEvents() {
|
|
// 导出按钮点击
|
|
document.getElementById('exportBtn').addEventListener('click', function() {
|
|
showToast('导出成功');
|
|
});
|
|
|
|
// 图表类型切换
|
|
document.querySelectorAll('.chart-type-btn').forEach(btn => {
|
|
btn.addEventListener('click', function() {
|
|
// 更新激活状态
|
|
document.querySelectorAll('.chart-type-btn').forEach(b => {
|
|
b.classList.remove('active');
|
|
b.setAttribute('aria-selected', 'false');
|
|
});
|
|
this.classList.add('active');
|
|
this.setAttribute('aria-selected', 'true');
|
|
|
|
// 更新图表类型并重绘
|
|
const chartType = this.dataset.type;
|
|
currentTrendType = chartType;
|
|
renderTrendChart();
|
|
updateChartCardVisibility(chartType);
|
|
});
|
|
});
|
|
|
|
// 月/年切换
|
|
document.querySelectorAll('.period-tab').forEach(tab => {
|
|
tab.addEventListener('click', function() {
|
|
document.querySelectorAll('.period-tab').forEach(t => t.classList.remove('active'));
|
|
this.classList.add('active');
|
|
currentPeriod = this.dataset.period;
|
|
// 实际项目中这里会根据period重新请求数据
|
|
// 目前为原型演示,数据不变
|
|
});
|
|
});
|
|
|
|
// 窗口大小变化时,重新渲染图表(响应式resize)
|
|
window.addEventListener('resize', function() {
|
|
trendChart && trendChart.resize();
|
|
expensePieChart && expensePieChart.resize();
|
|
compareChart && compareChart.resize();
|
|
});
|
|
|
|
// 监听侧边栏折叠事件,重新渲染图表
|
|
document.addEventListener('sidebarToggle', function(e) {
|
|
// 延迟resize,等待CSS过渡完成
|
|
setTimeout(function() {
|
|
trendChart && trendChart.resize();
|
|
expensePieChart && expensePieChart.resize();
|
|
compareChart && compareChart.resize();
|
|
}, 350);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* 页面初始化
|
|
*/
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
initTrendChart();
|
|
initExpensePieChart();
|
|
initCompareChart();
|
|
bindEvents();
|
|
// 设置初始卡片可见性(默认折线图)
|
|
updateChartCardVisibility('line');
|
|
});
|
|
</script>
|
|
<!-- 侧边栏折叠功能 -->
|
|
<script src="./js/sidebar.js"></script>
|
|
</body>
|
|
</html> |