feat:增加账本统计模块

This commit is contained in:
2025-10-30 23:02:55 +08:00
parent 9e0b8ead79
commit 355a6c256d
7 changed files with 140 additions and 6 deletions

View File

@@ -13,6 +13,7 @@
import { onMounted, ref } from 'vue'
import { useLedgerStore } from '@/store/ledger.ts'
import { ICategory } from '@/types'
import { statsByField } from '@/utils/home/ledgerUtil.ts'
const ledgerStore = useLedgerStore()

View File

@@ -115,6 +115,11 @@
<i class="fa-solid fa-list-ul"></i>
<span>清单</span>
</router-link>
<router-link v-if="path.includes('ledger')" to="/ledger/stats"
@click="routerClick()" class="item">
<i class="fa-solid fa-chart-pie"></i>
<span>统计</span>
</router-link>
<router-link v-if="path.includes('password')" to="/password/list"
@click="routerClick()" class="item">

View File

@@ -2,7 +2,6 @@ import { defineStore } from 'pinia'
import type { IDialog, IHandleApi, IStatsChart } from 'vue3-common/types'
import { ElMessage } from 'element-plus'
import { ILedger, ILedgerQuery, ILedgerRecord } from '@/types/ledger'
import { queryAssetCategoryApi } from '@/apis/asset'
import {
addLedgerApi,
deleteLedgerApi,

View File

@@ -0,0 +1,24 @@
import { ILedgerRecord } from '@/types/ledger.ts'
import { IStatsChart } from 'vue3-common/types'
export const statsByField = (records: ILedgerRecord[],
field: keyof ILedgerRecord): IStatsChart[] => {
const statsMap = new Map<string, number>()
records.forEach((record) => {
const fieldValue = record[field] as string
const filedStats = record.totalPrice as number
const currentTotal = statsMap.get(fieldValue) || 0
// 计算当前字段对应的统计数据
statsMap.set(fieldValue, currentTotal + filedStats)
})
return Array.from(statsMap.entries())
.map(([name, value]) => ({
name,
value: Number(value.toFixed(2))
}))
.sort((a, b) => b.value - a.value)
.slice(0, 5)
}

View File

@@ -23,17 +23,12 @@ import LedgerQuery from '@/components/Ledger/LedgerQuery.vue'
import LedgerCard from '@/components/Ledger/LedgerCard.vue'
import DraggableButton from '@/components/Common/DraggableButton.vue'
import { useLedgerStore } from '@/store/ledger.ts'
import { onMounted } from 'vue'
import { useRouter } from 'vue-router'
import { formatAmount } from 'vue3-common/utils/numberUtil'
const ledgerStore = useLedgerStore()
const router = useRouter()
onMounted(async () => {
// await ledgerStore.queryLedgerList()
})
const addClick = () => {
ledgerStore.ledgerApiType = 'ADD'
ledgerStore.currentLedgerRecord = ledgerStore.getEmptyLedgerRecord()

106
src/views/ledger/stats.vue Normal file
View File

@@ -0,0 +1,106 @@
<template>
<div class="mobile-ledger-stats common-mobile-view">
<div class="ledger-chart">
<div class="chart-container card-item">
<div class="content">
<span class="title">📊类别统计</span>
</div>
<div class="chart" ref="ledgerCategoryChartRef"/>
</div>
<div class="chart-container card-item">
<div class="content">
<span class="title">📊付款人统计</span>
</div>
<div class="chart" ref="ledgerPayerChartRef"/>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { useLedgerStore } from '@/store/ledger.ts'
import { onMounted, ref } from 'vue'
import { statsByField } from '@/utils/home/ledgerUtil.ts'
import { isMobile } from 'vue3-common/utils/layoutUtil'
import { useAppStore } from '@/store/app.ts'
import * as echarts from 'echarts'
import { pieChartOptions } from 'vue3-common/utils/eChartsUtil'
const ledgerStore = useLedgerStore()
const appStore = useAppStore()
const ledgerCategoryChartRef = ref<HTMLElement>()
const ledgerPayerChartRef = ref<HTMLElement>()
let ledgerCategoryChart: echarts.ECharts
let ledgerPayerChart: echarts.ECharts
onMounted(() => {
ledgerCategoryChart = echarts.init(ledgerCategoryChartRef.value as HTMLElement, appStore.isDark ? 'dark' : null)
ledgerPayerChart = echarts.init(ledgerPayerChartRef.value as HTMLElement, appStore.isDark ? 'dark' : null)
updateChart()
})
const updateChart = () => {
const categoryData = statsByField(ledgerStore.ledgerRecordList, 'category')
const payerData = statsByField(ledgerStore.ledgerRecordList, 'payer')
ledgerCategoryChart.setOption(pieChartOptions('rank', '元', categoryData))
ledgerPayerChart.setOption(pieChartOptions('rank', '元', payerData))
if (isMobile()) {
ledgerCategoryChart.setOption({
series: [{
radius: ['20%', '50%'],
label: {
formatter: '{b}: {d}%'
}
}]
})
ledgerPayerChart.setOption({
series: [{
radius: ['20%', '50%'],
label: {
formatter: '{b}: {d}%'
}
}]
})
}
}
</script>
<style lang="scss">
.mobile-ledger-stats {
display: flex;
flex-direction: column;
gap: 10px;
.ledger-chart {
flex-grow: 1;
display: grid;
grid-template-rows: repeat(2, 1fr);
gap: 10px;
.chart-container {
display: grid;
grid-template-rows: 40px 1fr;
.content {
padding: 0 5px;
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 1px solid #009FA8;
.title {
font-size: 1em;
font-weight: bold;
}
}
}
}
}
</style>

View File

@@ -199,6 +199,10 @@ export const mobileHomeMeta: IRouteMetaConfig = {
title: '清单',
icon: ''
},
'/ledger/stats': {
title: '统计',
icon: ''
},
'/ledger/detail/id': {
title: '内容',
icon: ''