fix
This commit is contained in:
@@ -153,7 +153,7 @@ const router = useRouter()
|
||||
const messageStore = useMessageStore()
|
||||
|
||||
// 主题
|
||||
const theme = computed(() => messageStore.isDarkMode ? 'dark' : 'light')
|
||||
const theme = computed(() => (messageStore.isDarkMode ? 'dark' : 'light'))
|
||||
|
||||
// 状态管理
|
||||
const loading = ref(false)
|
||||
@@ -196,8 +196,16 @@ const noneCategories = ref([])
|
||||
|
||||
// 颜色配置
|
||||
const categoryColors = [
|
||||
'#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4', '#FFEAA7',
|
||||
'#DDA0DD', '#98D8C8', '#F7DC6F', '#BB8FCE', '#85C1E9'
|
||||
'#FF6B6B',
|
||||
'#4ECDC4',
|
||||
'#45B7D1',
|
||||
'#96CEB4',
|
||||
'#FFEAA7',
|
||||
'#DDA0DD',
|
||||
'#98D8C8',
|
||||
'#F7DC6F',
|
||||
'#BB8FCE',
|
||||
'#85C1E9'
|
||||
]
|
||||
|
||||
// 计算属性
|
||||
@@ -266,7 +274,6 @@ const loadStatistics = async () => {
|
||||
|
||||
// 加载分类统计
|
||||
await loadCategoryStatistics(year, month)
|
||||
|
||||
} catch (error) {
|
||||
console.error('加载统计数据失败:', error)
|
||||
hasError.value = true
|
||||
@@ -303,8 +310,8 @@ const loadMonthlyData = async (year, month) => {
|
||||
if (dailyResult?.success && dailyResult.data) {
|
||||
// 转换数据格式:添加完整的 date 字段
|
||||
trendStats.value = dailyResult.data
|
||||
.filter(item => item != null)
|
||||
.map(item => ({
|
||||
.filter((item) => item != null)
|
||||
.map((item) => ({
|
||||
date: `${year}-${month.toString().padStart(2, '0')}-${item.day.toString().padStart(2, '0')}`,
|
||||
expense: item.expense || 0,
|
||||
income: item.income || 0,
|
||||
@@ -323,15 +330,18 @@ const loadYearlyData = async (year) => {
|
||||
const trendResult = await getTrendStatistics({ startYear: year, startMonth: 1, monthCount: 12 })
|
||||
if (trendResult?.success && trendResult.data) {
|
||||
// 计算年度汇总
|
||||
const yearTotal = trendResult.data.reduce((acc, item) => {
|
||||
const expense = item.expense || 0
|
||||
const income = item.income || 0
|
||||
return {
|
||||
totalExpense: acc.totalExpense + expense,
|
||||
totalIncome: acc.totalIncome + income,
|
||||
balance: acc.balance + income - expense
|
||||
}
|
||||
}, { totalExpense: 0, totalIncome: 0, balance: 0 })
|
||||
const yearTotal = trendResult.data.reduce(
|
||||
(acc, item) => {
|
||||
const expense = item.expense || 0
|
||||
const income = item.income || 0
|
||||
return {
|
||||
totalExpense: acc.totalExpense + expense,
|
||||
totalIncome: acc.totalIncome + income,
|
||||
balance: acc.balance + income - expense
|
||||
}
|
||||
},
|
||||
{ totalExpense: 0, totalIncome: 0, balance: 0 }
|
||||
)
|
||||
|
||||
monthlyStats.value = {
|
||||
...yearTotal,
|
||||
@@ -339,7 +349,7 @@ const loadYearlyData = async (year) => {
|
||||
incomeCount: 0
|
||||
}
|
||||
|
||||
trendStats.value = trendResult.data.map(item => ({
|
||||
trendStats.value = trendResult.data.map((item) => ({
|
||||
date: `${item.year}-${item.month.toString().padStart(2, '0')}-01`,
|
||||
amount: (item.income || 0) - (item.expense || 0),
|
||||
count: 1
|
||||
@@ -371,7 +381,8 @@ const loadWeeklyData = async () => {
|
||||
monthlyStats.value = {
|
||||
totalExpense: weekSummaryResult.data.totalExpense || 0,
|
||||
totalIncome: weekSummaryResult.data.totalIncome || 0,
|
||||
balance: (weekSummaryResult.data.totalIncome || 0) - (weekSummaryResult.data.totalExpense || 0),
|
||||
balance:
|
||||
(weekSummaryResult.data.totalIncome || 0) - (weekSummaryResult.data.totalExpense || 0),
|
||||
expenseCount: weekSummaryResult.data.expenseCount || 0,
|
||||
incomeCount: weekSummaryResult.data.incomeCount || 0
|
||||
}
|
||||
@@ -450,7 +461,11 @@ const loadCategoryStatistics = async (year, month) => {
|
||||
const currentColors = getChartColors()
|
||||
|
||||
// 处理支出分类结果
|
||||
if (expenseResult.status === 'fulfilled' && expenseResult.value?.success && expenseResult.value.data) {
|
||||
if (
|
||||
expenseResult.status === 'fulfilled' &&
|
||||
expenseResult.value?.success &&
|
||||
expenseResult.value.data
|
||||
) {
|
||||
expenseCategories.value = expenseResult.value.data.map((item, index) => ({
|
||||
classify: item.classify,
|
||||
amount: item.amount || 0,
|
||||
@@ -461,7 +476,11 @@ const loadCategoryStatistics = async (year, month) => {
|
||||
}
|
||||
|
||||
// 处理收入分类结果
|
||||
if (incomeResult.status === 'fulfilled' && incomeResult.value?.success && incomeResult.value.data) {
|
||||
if (
|
||||
incomeResult.status === 'fulfilled' &&
|
||||
incomeResult.value?.success &&
|
||||
incomeResult.value.data
|
||||
) {
|
||||
incomeCategories.value = incomeResult.value.data.map((item) => ({
|
||||
classify: item.classify,
|
||||
amount: item.amount || 0,
|
||||
@@ -510,7 +529,11 @@ const loadCategoryStatistics = async (year, month) => {
|
||||
const currentColors = getChartColors()
|
||||
|
||||
// 处理支出分类结果
|
||||
if (expenseResult.status === 'fulfilled' && expenseResult.value?.success && expenseResult.value.data) {
|
||||
if (
|
||||
expenseResult.status === 'fulfilled' &&
|
||||
expenseResult.value?.success &&
|
||||
expenseResult.value.data
|
||||
) {
|
||||
expenseCategories.value = expenseResult.value.data.map((item, index) => ({
|
||||
classify: item.classify,
|
||||
amount: item.amount || 0,
|
||||
@@ -521,7 +544,11 @@ const loadCategoryStatistics = async (year, month) => {
|
||||
}
|
||||
|
||||
// 处理收入分类结果
|
||||
if (incomeResult.status === 'fulfilled' && incomeResult.value?.success && incomeResult.value.data) {
|
||||
if (
|
||||
incomeResult.status === 'fulfilled' &&
|
||||
incomeResult.value?.success &&
|
||||
incomeResult.value.data
|
||||
) {
|
||||
incomeCategories.value = incomeResult.value.data.map((item) => ({
|
||||
classify: item.classify,
|
||||
amount: item.amount || 0,
|
||||
@@ -618,8 +645,7 @@ const isLastPeriod = () => {
|
||||
}
|
||||
case 'month': {
|
||||
// 比较年月
|
||||
return current.getFullYear() === now.getFullYear() &&
|
||||
current.getMonth() === now.getMonth()
|
||||
return current.getFullYear() === now.getFullYear() && current.getMonth() === now.getMonth()
|
||||
}
|
||||
case 'year': {
|
||||
// 比较年份
|
||||
@@ -717,20 +743,14 @@ watch(currentPeriod, () => {
|
||||
if (currentPeriod.value === 'year') {
|
||||
selectedDate.value = [currentDate.value.getFullYear()]
|
||||
} else {
|
||||
selectedDate.value = [
|
||||
currentDate.value.getFullYear(),
|
||||
currentDate.value.getMonth() + 1
|
||||
]
|
||||
selectedDate.value = [currentDate.value.getFullYear(), currentDate.value.getMonth() + 1]
|
||||
}
|
||||
})
|
||||
|
||||
// 初始化
|
||||
onMounted(() => {
|
||||
// 设置默认选中日期
|
||||
selectedDate.value = [
|
||||
currentDate.value.getFullYear(),
|
||||
currentDate.value.getMonth() + 1
|
||||
]
|
||||
selectedDate.value = [currentDate.value.getFullYear(), currentDate.value.getMonth() + 1]
|
||||
loadStatistics()
|
||||
})
|
||||
</script>
|
||||
@@ -792,4 +812,4 @@ onMounted(() => {
|
||||
padding-bottom: calc(95px + env(safe-area-inset-bottom, 0px));
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -101,7 +101,7 @@ const updateChart = () => {
|
||||
if (props.period === 'week') {
|
||||
// 周统计:直接使用传入的数据,按日期排序
|
||||
chartData = [...props.data].sort((a, b) => new Date(a.date) - new Date(b.date))
|
||||
xAxisLabels = chartData.map(item => {
|
||||
xAxisLabels = chartData.map((item) => {
|
||||
const date = new Date(item.date)
|
||||
const weekDays = ['日', '一', '二', '三', '四', '五', '六']
|
||||
return weekDays[date.getDay()]
|
||||
@@ -121,14 +121,14 @@ const updateChart = () => {
|
||||
|
||||
// 创建完整的数据映射
|
||||
const dataMap = new Map()
|
||||
props.data.forEach(item => {
|
||||
props.data.forEach((item) => {
|
||||
if (item && item.date) {
|
||||
dataMap.set(item.date, item)
|
||||
}
|
||||
})
|
||||
|
||||
// 生成完整的数据序列
|
||||
chartData = allDays.map(date => {
|
||||
chartData = allDays.map((date) => {
|
||||
const dayData = dataMap.get(date)
|
||||
return {
|
||||
date,
|
||||
@@ -141,9 +141,9 @@ const updateChart = () => {
|
||||
} else if (props.period === 'year') {
|
||||
// 年统计:直接使用数据,显示月份标签
|
||||
chartData = [...props.data]
|
||||
.filter(item => item && item.date)
|
||||
.filter((item) => item && item.date)
|
||||
.sort((a, b) => new Date(a.date) - new Date(b.date))
|
||||
xAxisLabels = chartData.map(item => {
|
||||
xAxisLabels = chartData.map((item) => {
|
||||
const date = new Date(item.date)
|
||||
return `${date.getMonth() + 1}月`
|
||||
})
|
||||
@@ -153,27 +153,29 @@ const updateChart = () => {
|
||||
if (chartData.length === 0) {
|
||||
const option = {
|
||||
backgroundColor: 'transparent',
|
||||
graphic: [{
|
||||
type: 'text',
|
||||
left: 'center',
|
||||
top: 'middle',
|
||||
style: {
|
||||
text: '暂无数据',
|
||||
fontSize: 16,
|
||||
fill: messageStore.isDarkMode ? '#9CA3AF' : '#6B7280'
|
||||
graphic: [
|
||||
{
|
||||
type: 'text',
|
||||
left: 'center',
|
||||
top: 'middle',
|
||||
style: {
|
||||
text: '暂无数据',
|
||||
fontSize: 16,
|
||||
fill: messageStore.isDarkMode ? '#9CA3AF' : '#6B7280'
|
||||
}
|
||||
}
|
||||
}]
|
||||
]
|
||||
}
|
||||
chartInstance.setOption(option)
|
||||
return
|
||||
}
|
||||
|
||||
// 准备图表数据
|
||||
const expenseData = chartData.map(item => {
|
||||
const expenseData = chartData.map((item) => {
|
||||
const amount = item.amount || 0
|
||||
return amount < 0 ? Math.abs(amount) : 0
|
||||
})
|
||||
const incomeData = chartData.map(item => {
|
||||
const incomeData = chartData.map((item) => {
|
||||
const amount = item.amount || 0
|
||||
return amount > 0 ? amount : 0
|
||||
})
|
||||
@@ -305,18 +307,25 @@ const updateChart = () => {
|
||||
}
|
||||
|
||||
// 监听数据变化
|
||||
watch(() => props.data, () => {
|
||||
if (chartInstance) {
|
||||
updateChart()
|
||||
}
|
||||
}, { deep: true })
|
||||
watch(
|
||||
() => props.data,
|
||||
() => {
|
||||
if (chartInstance) {
|
||||
updateChart()
|
||||
}
|
||||
},
|
||||
{ deep: true }
|
||||
)
|
||||
|
||||
// 监听主题变化
|
||||
watch(() => messageStore.isDarkMode, () => {
|
||||
if (chartInstance) {
|
||||
updateChart()
|
||||
watch(
|
||||
() => messageStore.isDarkMode,
|
||||
() => {
|
||||
if (chartInstance) {
|
||||
updateChart()
|
||||
}
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
onMounted(() => {
|
||||
initChart()
|
||||
@@ -358,4 +367,4 @@ onBeforeUnmount(() => {
|
||||
width: 100%;
|
||||
height: 180px;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -24,4 +24,4 @@ const emit = defineEmits(['category-click'])
|
||||
const handleCategoryClick = (classify, type) => {
|
||||
emit('category-click', classify, type)
|
||||
}
|
||||
</script>
|
||||
</script>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<!-- 支出分类统计 -->
|
||||
<div
|
||||
class="common-card"
|
||||
style="padding-bottom: 10px;"
|
||||
style="padding-bottom: 10px"
|
||||
>
|
||||
<div class="card-header">
|
||||
<h3 class="card-title">
|
||||
@@ -255,11 +255,15 @@ const renderPieChart = () => {
|
||||
}
|
||||
|
||||
// 监听数据变化重新渲染图表
|
||||
watch(() => [props.categories, props.totalExpense, props.colors], () => {
|
||||
nextTick(() => {
|
||||
renderPieChart()
|
||||
})
|
||||
}, { deep: true, immediate: true })
|
||||
watch(
|
||||
() => [props.categories, props.totalExpense, props.colors],
|
||||
() => {
|
||||
nextTick(() => {
|
||||
renderPieChart()
|
||||
})
|
||||
},
|
||||
{ deep: true, immediate: true }
|
||||
)
|
||||
|
||||
// 组件销毁时清理图表实例
|
||||
onBeforeUnmount(() => {
|
||||
@@ -404,4 +408,4 @@ onBeforeUnmount(() => {
|
||||
padding: 2px 8px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -41,8 +41,8 @@ const props = defineProps({
|
||||
})
|
||||
|
||||
const balanceClass = computed(() => ({
|
||||
'positive': props.balance >= 0,
|
||||
'negative': props.balance < 0
|
||||
positive: props.balance >= 0,
|
||||
negative: props.balance < 0
|
||||
}))
|
||||
</script>
|
||||
|
||||
@@ -90,4 +90,4 @@ const balanceClass = computed(() => ({
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -24,4 +24,4 @@ const emit = defineEmits(['category-click'])
|
||||
const handleCategoryClick = (classify, type) => {
|
||||
emit('category-click', classify, type)
|
||||
}
|
||||
</script>
|
||||
</script>
|
||||
|
||||
@@ -269,4 +269,4 @@ const noneCategories = computed(() => {
|
||||
.none-text {
|
||||
color: var(--van-gray-6);
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -80,8 +80,8 @@ let chartInstance = null
|
||||
|
||||
// 计算结余样式类
|
||||
const balanceClass = computed(() => ({
|
||||
'positive': props.balance >= 0,
|
||||
'negative': props.balance < 0
|
||||
positive: props.balance >= 0,
|
||||
negative: props.balance < 0
|
||||
}))
|
||||
|
||||
// 计算图表标题
|
||||
@@ -152,7 +152,7 @@ const updateChart = () => {
|
||||
if (props.period === 'week') {
|
||||
// 周统计:直接使用传入的数据,按日期排序
|
||||
chartData = [...props.trendData].sort((a, b) => new Date(a.date) - new Date(b.date))
|
||||
xAxisLabels = chartData.map(item => {
|
||||
xAxisLabels = chartData.map((item) => {
|
||||
const date = new Date(item.date)
|
||||
const weekDays = ['日', '一', '二', '三', '四', '五', '六']
|
||||
return weekDays[date.getDay()]
|
||||
@@ -172,14 +172,14 @@ const updateChart = () => {
|
||||
|
||||
// 创建完整的数据映射
|
||||
const dataMap = new Map()
|
||||
props.trendData.forEach(item => {
|
||||
props.trendData.forEach((item) => {
|
||||
if (item && item.date) {
|
||||
dataMap.set(item.date, item)
|
||||
}
|
||||
})
|
||||
|
||||
// 生成完整的数据序列
|
||||
chartData = allDays.map(date => {
|
||||
chartData = allDays.map((date) => {
|
||||
const dayData = dataMap.get(date)
|
||||
return {
|
||||
date,
|
||||
@@ -193,9 +193,9 @@ const updateChart = () => {
|
||||
} else if (props.period === 'year') {
|
||||
// 年统计:直接使用数据,显示月份标签
|
||||
chartData = [...props.trendData]
|
||||
.filter(item => item && item.date)
|
||||
.filter((item) => item && item.date)
|
||||
.sort((a, b) => new Date(a.date) - new Date(b.date))
|
||||
xAxisLabels = chartData.map(item => {
|
||||
xAxisLabels = chartData.map((item) => {
|
||||
const date = new Date(item.date)
|
||||
return `${date.getMonth() + 1}月`
|
||||
})
|
||||
@@ -205,16 +205,18 @@ const updateChart = () => {
|
||||
if (chartData.length === 0) {
|
||||
const option = {
|
||||
backgroundColor: 'transparent',
|
||||
graphic: [{
|
||||
type: 'text',
|
||||
left: 'center',
|
||||
top: 'middle',
|
||||
style: {
|
||||
text: '暂无数据',
|
||||
fontSize: 16,
|
||||
fill: messageStore.isDarkMode ? '#9CA3AF' : '#6B7280'
|
||||
graphic: [
|
||||
{
|
||||
type: 'text',
|
||||
left: 'center',
|
||||
top: 'middle',
|
||||
style: {
|
||||
text: '暂无数据',
|
||||
fontSize: 16,
|
||||
fill: messageStore.isDarkMode ? '#9CA3AF' : '#6B7280'
|
||||
}
|
||||
}
|
||||
}]
|
||||
]
|
||||
}
|
||||
chartInstance.setOption(option)
|
||||
return
|
||||
@@ -227,7 +229,7 @@ const updateChart = () => {
|
||||
const expenseData = []
|
||||
const incomeData = []
|
||||
|
||||
chartData.forEach(item => {
|
||||
chartData.forEach((item) => {
|
||||
// 支持两种数据格式:1) expense/income字段 2) amount字段(兼容旧数据)
|
||||
let expense = 0
|
||||
let income = 0
|
||||
@@ -401,18 +403,25 @@ const updateChart = () => {
|
||||
}
|
||||
|
||||
// 监听数据变化
|
||||
watch(() => props.trendData, () => {
|
||||
if (chartInstance) {
|
||||
updateChart()
|
||||
}
|
||||
}, { deep: true })
|
||||
watch(
|
||||
() => props.trendData,
|
||||
() => {
|
||||
if (chartInstance) {
|
||||
updateChart()
|
||||
}
|
||||
},
|
||||
{ deep: true }
|
||||
)
|
||||
|
||||
// 监听主题变化
|
||||
watch(() => messageStore.isDarkMode, () => {
|
||||
if (chartInstance) {
|
||||
updateChart()
|
||||
watch(
|
||||
() => messageStore.isDarkMode,
|
||||
() => {
|
||||
if (chartInstance) {
|
||||
updateChart()
|
||||
}
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
onMounted(() => {
|
||||
initChart()
|
||||
|
||||
Reference in New Issue
Block a user