You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
381 lines
9.0 KiB
381 lines
9.0 KiB
1 week ago
|
// 引入wx-chart图表库
|
||
|
import WxChart from '../utils/wx-chart.js';
|
||
|
|
||
|
Page({
|
||
|
data: {
|
||
|
// 当前时间类型:year, month, quarter
|
||
|
currentTimeType: 'year',
|
||
|
// 当前周期文本
|
||
|
currentPeriodText: '2023年',
|
||
|
// 当前选中的饼图类型:income, expense
|
||
|
currentPieType: 'income',
|
||
|
// 收入总额
|
||
|
incomeTotal: '¥128,500.00',
|
||
|
// 支出总额
|
||
|
expenseTotal: '¥85,300.00',
|
||
|
// 当前选中的标签页
|
||
|
currentTab: 'statistics',
|
||
|
// 饼图图例数据
|
||
|
currentPieLegend: [],
|
||
|
|
||
|
// 图表实例
|
||
|
trendChart: null,
|
||
|
categoryChart: null,
|
||
|
|
||
|
// 时间数据
|
||
|
timeData: {
|
||
|
year: {
|
||
|
labels: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'],
|
||
|
income: [8500, 9200, 10500, 9800, 11200, 12500, 11800, 13200, 12800, 14500, 13800, 15200],
|
||
|
expense: [6200, 5800, 6500, 7200, 6800, 7500, 8200, 7800, 8500, 7900, 8200, 8800],
|
||
|
totalIncome: 128500,
|
||
|
totalExpense: 85300
|
||
|
},
|
||
|
month: {
|
||
|
labels: ['第1周', '第2周', '第3周', '第4周', '第5周'],
|
||
|
income: [3200, 3800, 3500, 4200, 2800],
|
||
|
expense: [2100, 2500, 1900, 2300, 1800],
|
||
|
totalIncome: 17500,
|
||
|
totalExpense: 10600
|
||
|
},
|
||
|
quarter: {
|
||
|
labels: ['Q1', 'Q2', 'Q3', 'Q4'],
|
||
|
income: [28200, 33500, 37800, 29000],
|
||
|
expense: [18500, 21800, 24500, 20500],
|
||
|
totalIncome: 128500,
|
||
|
totalExpense: 85300
|
||
|
}
|
||
|
},
|
||
|
|
||
|
// 分类数据
|
||
|
categoryData: {
|
||
|
income: {
|
||
|
categories: ['工资', '奖金', '投资收益', '兼职', '其他'],
|
||
|
data: [80000, 20000, 15000, 10000, 3500],
|
||
|
colors: [
|
||
|
'rgba(59, 130, 246, 0.8)',
|
||
|
'rgba(59, 130, 246, 0.7)',
|
||
|
'rgba(59, 130, 246, 0.6)',
|
||
|
'rgba(59, 130, 246, 0.5)',
|
||
|
'rgba(59, 130, 246, 0.4)'
|
||
|
]
|
||
|
},
|
||
|
expense: {
|
||
|
categories: ['餐饮', '住房', '交通', '购物', '娱乐', '其他'],
|
||
|
data: [25000, 30000, 8000, 12000, 5300, 5000],
|
||
|
colors: [
|
||
|
'rgba(239, 68, 68, 0.8)',
|
||
|
'rgba(239, 68, 68, 0.7)',
|
||
|
'rgba(239, 68, 68, 0.6)',
|
||
|
'rgba(239, 68, 68, 0.5)',
|
||
|
'rgba(239, 68, 68, 0.4)',
|
||
|
'rgba(239, 68, 68, 0.3)'
|
||
|
]
|
||
|
}
|
||
|
},
|
||
|
|
||
|
// 当前时间
|
||
|
currentDate: {
|
||
|
year: 2023,
|
||
|
month: 1,
|
||
|
quarter: 1
|
||
|
}
|
||
|
},
|
||
|
|
||
|
onLoad() {
|
||
|
// 初始化图表
|
||
|
this.initCharts();
|
||
|
// 初始化饼图图例
|
||
|
this.updatePieLegend('income');
|
||
|
},
|
||
|
|
||
|
onReady() {
|
||
|
// 页面渲染完成后执行
|
||
|
},
|
||
|
|
||
|
// 初始化图表
|
||
|
initCharts() {
|
||
|
// 初始化趋势图
|
||
|
this.initTrendChart();
|
||
|
// 初始化饼图
|
||
|
this.initPieChart();
|
||
|
},
|
||
|
|
||
|
// 初始化趋势图
|
||
|
initTrendChart() {
|
||
|
const ctx = wx.createCanvasContext('trendChart', this);
|
||
|
const data = this.data.timeData[this.data.currentTimeType];
|
||
|
|
||
|
this.data.trendChart = new WxChart({
|
||
|
canvasId: 'trendChart',
|
||
|
type: 'line',
|
||
|
categories: data.labels,
|
||
|
series: [
|
||
|
{
|
||
|
name: '收入',
|
||
|
data: data.income,
|
||
|
color: '#3B82F6',
|
||
|
format: function (val) {
|
||
|
return '¥' + val.toFixed(0);
|
||
|
}
|
||
|
},
|
||
|
{
|
||
|
name: '支出',
|
||
|
data: data.expense,
|
||
|
color: '#EF4444',
|
||
|
format: function (val) {
|
||
|
return '¥' + val.toFixed(0);
|
||
|
}
|
||
|
}
|
||
|
],
|
||
|
yAxis: {
|
||
|
title: '金额 (¥)',
|
||
|
format: function (val) {
|
||
|
return val.toLocaleString();
|
||
|
},
|
||
|
min: 0
|
||
|
},
|
||
|
xAxis: {
|
||
|
disableGrid: true
|
||
|
},
|
||
|
extra: {
|
||
|
lineStyle: 'curve'
|
||
|
}
|
||
|
});
|
||
|
},
|
||
|
|
||
|
// 初始化饼图
|
||
|
initPieChart() {
|
||
|
const ctx = wx.createCanvasContext('categoryChart', this);
|
||
|
const data = this.data.categoryData[this.data.currentPieType];
|
||
|
|
||
|
this.data.categoryChart = new WxChart({
|
||
|
canvasId: 'categoryChart',
|
||
|
type: 'pie',
|
||
|
series: data.data,
|
||
|
labels: data.categories,
|
||
|
colors: data.colors,
|
||
|
extra: {
|
||
|
pie: {
|
||
|
offsetAngle: -90,
|
||
|
radius: 80
|
||
|
}
|
||
|
},
|
||
|
format: function (val, name) {
|
||
|
const total = data.data.reduce((a, b) => a + b, 0);
|
||
|
const percentage = Math.round((val / total) * 100) + '%';
|
||
|
return `${name}: ¥${val.toLocaleString()} (${percentage})`;
|
||
|
}
|
||
|
});
|
||
|
},
|
||
|
|
||
|
// 切换时间类型
|
||
|
changeTimeType(e) {
|
||
|
const type = e.currentTarget.dataset.type;
|
||
|
if (this.data.currentTimeType === type) return;
|
||
|
|
||
|
this.setData({
|
||
|
currentTimeType: type
|
||
|
}, () => {
|
||
|
// 更新时间周期显示
|
||
|
this.updatePeriodDisplay();
|
||
|
// 更新趋势图数据
|
||
|
this.updateTrendChart();
|
||
|
// 更新总额显示
|
||
|
this.updateTotalAmounts();
|
||
|
});
|
||
|
},
|
||
|
|
||
|
// 更新时间周期显示
|
||
|
updatePeriodDisplay() {
|
||
|
const { year, month, quarter } = this.data.currentDate;
|
||
|
let text = '';
|
||
|
|
||
|
switch (this.data.currentTimeType) {
|
||
|
case 'year':
|
||
|
text = `${year}年`;
|
||
|
break;
|
||
|
case 'month':
|
||
|
text = `${year}年${month}月`;
|
||
|
break;
|
||
|
case 'quarter':
|
||
|
text = `${year}年第${quarter}季度`;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
this.setData({
|
||
|
currentPeriodText: text
|
||
|
});
|
||
|
},
|
||
|
|
||
|
// 更新趋势图数据
|
||
|
updateTrendChart() {
|
||
|
const data = this.data.timeData[this.data.currentTimeType];
|
||
|
|
||
|
this.data.trendChart.updateData({
|
||
|
categories: data.labels,
|
||
|
series: [
|
||
|
{
|
||
|
name: '收入',
|
||
|
data: data.income
|
||
|
},
|
||
|
{
|
||
|
name: '支出',
|
||
|
data: data.expense
|
||
|
}
|
||
|
]
|
||
|
});
|
||
|
},
|
||
|
|
||
|
// 更新总额显示
|
||
|
updateTotalAmounts() {
|
||
|
const data = this.data.timeData[this.data.currentTimeType];
|
||
|
|
||
|
this.setData({
|
||
|
incomeTotal: this.formatCurrency(data.totalIncome),
|
||
|
expenseTotal: this.formatCurrency(data.totalExpense)
|
||
|
});
|
||
|
},
|
||
|
|
||
|
// 切换饼图类型
|
||
|
changePieType(e) {
|
||
|
const type = e.currentTarget.dataset.type;
|
||
|
if (this.data.currentPieType === type) return;
|
||
|
|
||
|
this.setData({
|
||
|
currentPieType: type
|
||
|
}, () => {
|
||
|
// 更新饼图数据
|
||
|
this.updatePieChart();
|
||
|
// 更新饼图图例
|
||
|
this.updatePieLegend(type);
|
||
|
});
|
||
|
},
|
||
|
|
||
|
// 更新饼图数据
|
||
|
updatePieChart() {
|
||
|
const data = this.data.categoryData[this.data.currentPieType];
|
||
|
|
||
|
this.data.categoryChart.updateData({
|
||
|
series: data.data,
|
||
|
labels: data.categories,
|
||
|
colors: data.colors
|
||
|
});
|
||
|
},
|
||
|
|
||
|
// 更新饼图图例
|
||
|
updatePieLegend(type) {
|
||
|
const data = this.data.categoryData[type];
|
||
|
const total = data.data.reduce((a, b) => a + b, 0);
|
||
|
const legend = [];
|
||
|
|
||
|
data.categories.forEach((category, index) => {
|
||
|
const value = data.data[index];
|
||
|
const percentage = Math.round((value / total) * 100) + '%';
|
||
|
|
||
|
legend.push({
|
||
|
name: category,
|
||
|
value: this.formatCurrency(value),
|
||
|
percent: percentage,
|
||
|
color: data.colors[index]
|
||
|
});
|
||
|
});
|
||
|
|
||
|
this.setData({
|
||
|
currentPieLegend: legend
|
||
|
});
|
||
|
},
|
||
|
|
||
|
// 上一个周期
|
||
|
prevPeriod() {
|
||
|
const { currentDate, currentTimeType } = this.data;
|
||
|
const newDate = { ...currentDate };
|
||
|
|
||
|
switch (currentTimeType) {
|
||
|
case 'year':
|
||
|
newDate.year--;
|
||
|
break;
|
||
|
case 'month':
|
||
|
newDate.month--;
|
||
|
if (newDate.month < 1) {
|
||
|
newDate.month = 12;
|
||
|
newDate.year--;
|
||
|
}
|
||
|
break;
|
||
|
case 'quarter':
|
||
|
newDate.quarter--;
|
||
|
if (newDate.quarter < 1) {
|
||
|
newDate.quarter = 4;
|
||
|
newDate.year--;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
this.setData({
|
||
|
currentDate: newDate
|
||
|
}, () => {
|
||
|
this.updatePeriodDisplay();
|
||
|
// 实际应用中这里应该根据新日期请求数据
|
||
|
});
|
||
|
},
|
||
|
|
||
|
// 下一个周期
|
||
|
nextPeriod() {
|
||
|
const { currentDate, currentTimeType } = this.data;
|
||
|
const newDate = { ...currentDate };
|
||
|
|
||
|
switch (currentTimeType) {
|
||
|
case 'year':
|
||
|
newDate.year++;
|
||
|
break;
|
||
|
case 'month':
|
||
|
newDate.month++;
|
||
|
if (newDate.month > 12) {
|
||
|
newDate.month = 1;
|
||
|
newDate.year++;
|
||
|
}
|
||
|
break;
|
||
|
case 'quarter':
|
||
|
newDate.quarter++;
|
||
|
if (newDate.quarter > 4) {
|
||
|
newDate.quarter = 1;
|
||
|
newDate.year++;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
this.setData({
|
||
|
currentDate: newDate
|
||
|
}, () => {
|
||
|
this.updatePeriodDisplay();
|
||
|
// 实际应用中这里应该根据新日期请求数据
|
||
|
});
|
||
|
},
|
||
|
|
||
|
// 格式化货币
|
||
|
formatCurrency(value) {
|
||
|
return '¥' + value.toLocaleString('zh-CN', {
|
||
|
minimumFractionDigits: 2,
|
||
|
maximumFractionDigits: 2
|
||
|
});
|
||
|
},
|
||
|
|
||
|
// 趋势图点击事件
|
||
|
touchTrendChart(e) {
|
||
|
this.data.trendChart.showToolTip(e, {
|
||
|
format: function (item, category) {
|
||
|
return `${category} ${item.name}: ${item.data}`;
|
||
|
}
|
||
|
});
|
||
|
},
|
||
|
|
||
|
// 饼图点击事件
|
||
|
touchPieChart(e) {
|
||
|
this.data.categoryChart.showToolTip(e, {
|
||
|
format: function (item, category) {
|
||
|
return `${category}: ${item.data}`;
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
});
|