记账微信小程序
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.

210 lines
5.7 KiB

1 week ago
Page({
data: {
selectedMonth: '',
selectedMonthText: '',
summary: {
income: '0.00',
expense: '0.00',
balance: '0.00'
},
activeType: 'expense',
categoryStats: [],
monthRecords: []
},
onLoad() {
// 初始化当前月份
const today = new Date();
const year = today.getFullYear();
const month = String(today.getMonth() + 1).padStart(2, '0');
const selectedMonth = `${year}-${month}`;
this.setData({
selectedMonth,
selectedMonthText: `${year}${month}`
});
this.updateStatistics();
},
onMonthChange(e) {
const selectedMonth = e.detail.value;
const [year, month] = selectedMonth.split('-');
this.setData({
selectedMonth,
selectedMonthText: `${year}${month}`
});
this.updateStatistics();
},
setActiveType(e) {
const type = e.currentTarget.dataset.type;
this.setData({ activeType: type }, () => {
this.calculateCategoryStats();
this.drawPieChart();
});
},
updateStatistics() {
// 获取所有记录
const records = wx.getStorageSync('records') || [];
const [year, month] = this.data.selectedMonth.split('-');
// 筛选当月记录
const monthRecords = records.filter(record => {
const recordDate = new Date(record.date);
return recordDate.getFullYear() === parseInt(year) &&
(recordDate.getMonth() + 1) === parseInt(month);
});
// 按日期倒序排列
monthRecords.sort((a, b) => new Date(b.date) - new Date(a.date));
// 计算收支汇总
let income = 0;
let expense = 0;
monthRecords.forEach(record => {
if (record.type === 'income') {
income += parseFloat(record.amount);
} else {
expense += parseFloat(record.amount);
}
});
const balance = income - expense;
this.setData({
monthRecords,
summary: {
income: income.toFixed(2),
expense: expense.toFixed(2),
balance: balance.toFixed(2)
}
}, () => {
this.calculateCategoryStats();
this.drawPieChart();
});
},
calculateCategoryStats() {
const { monthRecords, activeType } = this.data;
const typeRecords = monthRecords.filter(record => record.type === activeType);
// 按分类汇总
const categoryMap = {};
typeRecords.forEach(record => {
if (!categoryMap[record.categoryId]) {
categoryMap[record.categoryId] = {
categoryId: record.categoryId,
categoryName: record.categoryName,
amount: 0,
count: 0
};
}
categoryMap[record.categoryId].amount += parseFloat(record.amount);
categoryMap[record.categoryId].count += 1;
});
// 转换为数组并排序
let categoryStats = Object.values(categoryMap);
categoryStats.sort((a, b) => b.amount - a.amount);
// 计算百分比
const total = activeType === 'income'
? parseFloat(this.data.summary.income)
: parseFloat(this.data.summary.expense);
if (total > 0) {
categoryStats.forEach(item => {
item.percentage = Math.round((item.amount / total) * 100);
item.amount = item.amount.toFixed(2);
});
}
// 分配颜色
const colors = ['#F44336', '#E91E63', '#9C27B0', '#673AB7', '#3F51B5', '#2196F3', '#03A9F4', '#00BCD4', '#009688', '#4CAF50', '#8BC34A', '#CDDC39'];
categoryStats.forEach((item, index) => {
item.color = colors[index % colors.length];
});
this.setData({ categoryStats });
},
drawPieChart() {
const { categoryStats } = this.data;
if (categoryStats.length === 0) {
return;
}
const ctx = wx.createCanvasContext('pieChart', this);
const centerX = 120; // 饼图中心X坐标
const centerY = 120; // 饼图中心Y坐标
const radius = 90; // 饼图半径
let startAngle = 0;
categoryStats.forEach(item => {
const percentage = parseFloat(item.percentage);
const endAngle = startAngle + 2 * Math.PI * (percentage / 100);
// 绘制扇形
ctx.beginPath();
ctx.setFillStyle(item.color);
ctx.moveTo(centerX, centerY);
ctx.arc(centerX, centerY, radius, startAngle, endAngle, false);
ctx.closePath();
ctx.fill();
// 计算文本位置
const midAngle = startAngle + (endAngle - startAngle) / 2;
const textRadius = radius * 0.6; // 文本距离中心的距离
const textX = centerX + Math.cos(midAngle) * textRadius;
const textY = centerY + Math.sin(midAngle) * textRadius;
// 绘制百分比文本
ctx.setFontSize(14);
ctx.setFillStyle('#333');
ctx.setTextAlign('center');
ctx.setTextBaseline('middle');
ctx.fillText(`${percentage}%`, textX, textY);
startAngle = endAngle;
});
// 绘制中心空白区域
ctx.beginPath();
ctx.setFillStyle('#ffffff');
ctx.arc(centerX, centerY, radius * 0.4, 0, 2 * Math.PI, false);
ctx.fill();
// 绘制中心文本
const total = this.data.activeType === 'income'
? this.data.summary.income
: this.data.summary.expense;
ctx.setFontSize(16);
ctx.setFillStyle('#333');
ctx.setTextAlign('center');
ctx.setTextBaseline('middle');
ctx.fillText(`总计`, centerX, centerY - 10);
ctx.setFontSize(18);
ctx.setFillStyle(this.data.activeType === 'income' ? '#4CAF50' : '#f44336');
ctx.fillText(`¥${total}`, centerX, centerY + 15);
ctx.draw();
},
formatDate(dateStr) {
const date = new Date(dateStr);
const month = date.getMonth() + 1;
const day = date.getDate();
return `${month}${day}`;
}
})