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.
315 lines
8.2 KiB
315 lines
8.2 KiB
const request = require('../utils/request')
|
|
Page({
|
|
data: {
|
|
// 当前时间类型:year, month, quarter
|
|
currentTimeType: 'year',
|
|
// 当前周期文本
|
|
currentPeriodText: '2023年',
|
|
// 当前时间
|
|
currentDate: {
|
|
year: 2023,
|
|
month: 1,
|
|
quarter: 1
|
|
},
|
|
selectedMonth: '',
|
|
selectedMonthText: '',
|
|
summary: {
|
|
income: '0.00',
|
|
expense: '0.00',
|
|
balance: '0.00'
|
|
},
|
|
activeType: 'expense',
|
|
categoryStats: [],
|
|
monthRecords: []
|
|
},
|
|
|
|
onShow() {
|
|
// 初始化当前月份
|
|
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}月`,
|
|
currentPeriodText:`${year}年`,
|
|
currentDate: {
|
|
year,
|
|
month
|
|
}
|
|
});
|
|
|
|
this.updateStatistics();
|
|
},
|
|
// 上一个周期
|
|
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();
|
|
// 实际应用中这里应该根据新日期请求数据
|
|
});
|
|
},
|
|
// 切换时间类型
|
|
changeTimeType(e) {
|
|
const type = e.currentTarget.dataset.type;
|
|
if (this.data.currentTimeType === type) return;
|
|
|
|
this.setData({
|
|
currentTimeType: type
|
|
}, () => {
|
|
|
|
this.updatePeriodDisplay();
|
|
|
|
});
|
|
},
|
|
// 更新时间周期显示
|
|
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
|
|
});
|
|
},
|
|
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();
|
|
});
|
|
},
|
|
|
|
async updateStatistics() {
|
|
// 筛选当月记录
|
|
const res = await request.get('/app-api/book/inout/allList')
|
|
let monthRecords=[]
|
|
if(res.code==0){
|
|
monthRecords=res.data
|
|
}
|
|
// 计算收支汇总
|
|
let income = 0;
|
|
let expense = 0;
|
|
|
|
const res1 = await request.get('/app-api/book/inout/myList-tol',{type:"in"})
|
|
console.log('获取数据成功:', res1)
|
|
if(res1.code==0){
|
|
income=res1.data
|
|
}
|
|
const res2 = await request.get('/app-api/book/inout/myList-tol',{type:"out"})
|
|
console.log('获取数据成功:', res2)
|
|
if(res2.code==0){
|
|
expense=res2.data
|
|
}
|
|
|
|
const balance = income - expense;
|
|
|
|
this.setData({
|
|
monthRecords,
|
|
summary: {
|
|
income: income.toFixed(2),
|
|
expense: expense.toFixed(2),
|
|
balance: balance.toFixed(2)
|
|
}
|
|
}, () => {
|
|
this.calculateCategoryStats();
|
|
});
|
|
},
|
|
|
|
async calculateCategoryStats() {
|
|
const { monthRecords, activeType } = this.data;
|
|
|
|
// 按分类汇总
|
|
const categoryMap = {};
|
|
const res3 = await request.get('/app-api/book/classification/group-one',{type:activeType=='expense'?"out":"in"})
|
|
console.log('获取数据成功:', res3)
|
|
if(res3.code==0){
|
|
res3.data.forEach(record => {
|
|
categoryMap[record.id] = {
|
|
categoryId: record.id,
|
|
categoryName: record.classificationName,
|
|
amount: record.money,
|
|
count: record.num,
|
|
};
|
|
});
|
|
}
|
|
|
|
|
|
// 转换为数组并排序
|
|
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 });
|
|
this.drawPieChart();
|
|
},
|
|
|
|
drawPieChart() {
|
|
const { categoryStats } = this.data;
|
|
console.log("drawPieChart:",categoryStats)
|
|
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}日`;
|
|
}
|
|
})
|
|
|