添加预算视图统计信息,显示本周、本月和年度达成率,优化样式和布局
This commit is contained in:
@@ -9,6 +9,31 @@
|
||||
<div class="page-content">
|
||||
<van-tabs v-model:active="activeTab" sticky offset-top="46" type="card">
|
||||
<van-tab title="支出" :name="BudgetCategory.Expense">
|
||||
<div class="summary-card common-card">
|
||||
<div class="summary-item">
|
||||
<div class="label">本周{{ activeTabTitle }}率</div>
|
||||
<div class="value" :class="getValueClass(overallStats.week.rate)">
|
||||
{{ overallStats.week.rate }}<span class="unit">%</span>
|
||||
</div>
|
||||
<div class="sub-label">{{ overallStats.week.count }}个预算</div>
|
||||
</div>
|
||||
<div class="divider"></div>
|
||||
<div class="summary-item">
|
||||
<div class="label">本月{{ activeTabTitle }}率</div>
|
||||
<div class="value" :class="getValueClass(overallStats.month.rate)">
|
||||
{{ overallStats.month.rate }}<span class="unit">%</span>
|
||||
</div>
|
||||
<div class="sub-label">{{ overallStats.month.count }}个预算</div>
|
||||
</div>
|
||||
<div class="divider"></div>
|
||||
<div class="summary-item">
|
||||
<div class="label">年度{{ activeTabTitle }}率</div>
|
||||
<div class="value" :class="getValueClass(overallStats.year.rate)">
|
||||
{{ overallStats.year.rate }}<span class="unit">%</span>
|
||||
</div>
|
||||
<div class="sub-label">{{ overallStats.year.count }}个预算</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="budget-list">
|
||||
<template v-if="expenseBudgets?.length > 0">
|
||||
<van-swipe-cell v-for="budget in expenseBudgets" :key="budget.id">
|
||||
@@ -20,8 +45,8 @@
|
||||
<van-tag v-else type="success" size="small" plain>进行中</van-tag>
|
||||
</div>
|
||||
<div class="header-actions">
|
||||
<van-button icon="replay" size="mini" plain round @click="handleSync(budget)" :loading="budget.syncing" />
|
||||
<van-button :icon="budget.isStopped ? 'play' : 'pause'" size="mini" plain round @click="handleToggleStop(budget)" />
|
||||
<van-button icon="replay" size="mini" plain @click="handleSync(budget)" :loading="budget.syncing" />
|
||||
<van-button :icon="budget.isStopped ? 'play' : 'pause'" size="mini" plain @click="handleToggleStop(budget)" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -78,6 +103,31 @@
|
||||
</van-tab>
|
||||
|
||||
<van-tab title="收入" :name="BudgetCategory.Income">
|
||||
<div class="summary-card common-card">
|
||||
<div class="summary-item">
|
||||
<div class="label">本周{{ activeTabTitle }}率</div>
|
||||
<div class="value" :class="getValueClass(overallStats.week.rate)">
|
||||
{{ overallStats.week.rate }}<span class="unit">%</span>
|
||||
</div>
|
||||
<div class="sub-label">{{ overallStats.week.count }}个预算</div>
|
||||
</div>
|
||||
<div class="divider"></div>
|
||||
<div class="summary-item">
|
||||
<div class="label">本月{{ activeTabTitle }}率</div>
|
||||
<div class="value" :class="getValueClass(overallStats.month.rate)">
|
||||
{{ overallStats.month.rate }}<span class="unit">%</span>
|
||||
</div>
|
||||
<div class="sub-label">{{ overallStats.month.count }}个预算</div>
|
||||
</div>
|
||||
<div class="divider"></div>
|
||||
<div class="summary-item">
|
||||
<div class="label">年度{{ activeTabTitle }}率</div>
|
||||
<div class="value" :class="getValueClass(overallStats.year.rate)">
|
||||
{{ overallStats.year.rate }}<span class="unit">%</span>
|
||||
</div>
|
||||
<div class="sub-label">{{ overallStats.year.count }}个预算</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="budget-list">
|
||||
<template v-if="incomeBudgets?.length > 0">
|
||||
<van-swipe-cell v-for="budget in incomeBudgets" :key="budget.id">
|
||||
@@ -147,6 +197,31 @@
|
||||
</van-tab>
|
||||
|
||||
<van-tab title="存款" :name="BudgetCategory.Savings">
|
||||
<div class="summary-card common-card">
|
||||
<div class="summary-item">
|
||||
<div class="label">本周{{ activeTabTitle }}率</div>
|
||||
<div class="value" :class="getValueClass(overallStats.week.rate)">
|
||||
{{ overallStats.week.rate }}<span class="unit">%</span>
|
||||
</div>
|
||||
<div class="sub-label">{{ overallStats.week.count }}个预算</div>
|
||||
</div>
|
||||
<div class="divider"></div>
|
||||
<div class="summary-item">
|
||||
<div class="label">本月{{ activeTabTitle }}率</div>
|
||||
<div class="value" :class="getValueClass(overallStats.month.rate)">
|
||||
{{ overallStats.month.rate }}<span class="unit">%</span>
|
||||
</div>
|
||||
<div class="sub-label">{{ overallStats.month.count }}个预算</div>
|
||||
</div>
|
||||
<div class="divider"></div>
|
||||
<div class="summary-item">
|
||||
<div class="label">年度{{ activeTabTitle }}率</div>
|
||||
<div class="value" :class="getValueClass(overallStats.year.rate)">
|
||||
{{ overallStats.year.rate }}<span class="unit">%</span>
|
||||
</div>
|
||||
<div class="sub-label">{{ overallStats.year.count }}个预算</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="budget-list">
|
||||
<template v-if="savingsBudgets?.length > 0">
|
||||
<van-swipe-cell v-for="budget in savingsBudgets" :key="budget.id">
|
||||
@@ -321,6 +396,53 @@ const expenseBudgets = ref([])
|
||||
const incomeBudgets = ref([])
|
||||
const savingsBudgets = ref([])
|
||||
|
||||
const activeTabTitle = computed(() => {
|
||||
if (activeTab.value === BudgetCategory.Expense) return '使用'
|
||||
return '达成'
|
||||
})
|
||||
|
||||
const overallStats = computed(() => {
|
||||
const allBudgets = [...expenseBudgets.value, ...incomeBudgets.value, ...savingsBudgets.value]
|
||||
|
||||
const getStatsForType = (type) => {
|
||||
const category = activeTab.value
|
||||
const filtered = allBudgets.filter(b => b.type === type && b.category === category && !b.isStopped)
|
||||
|
||||
if (filtered.length === 0) return { rate: '0.0', current: 0, limit: 0, count: 0 }
|
||||
|
||||
const current = filtered.reduce((sum, b) => sum + (b.current || 0), 0)
|
||||
const limit = filtered.reduce((sum, b) => sum + (b.limit || 0), 0)
|
||||
const rate = limit > 0 ? (current / limit) * 100 : 0
|
||||
|
||||
return {
|
||||
rate: rate.toFixed(1),
|
||||
current,
|
||||
limit,
|
||||
count: filtered.length
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
week: getStatsForType(BudgetPeriodType.Week),
|
||||
month: getStatsForType(BudgetPeriodType.Month),
|
||||
year: getStatsForType(BudgetPeriodType.Year)
|
||||
}
|
||||
})
|
||||
|
||||
const getValueClass = (rate) => {
|
||||
const numRate = parseFloat(rate)
|
||||
if (numRate === 0) return ''
|
||||
if (activeTab.value === BudgetCategory.Expense) {
|
||||
if (numRate >= 100) return 'expense'
|
||||
if (numRate >= 80) return 'warning'
|
||||
return 'income'
|
||||
} else {
|
||||
if (numRate >= 100) return 'income'
|
||||
if (numRate >= 80) return 'warning'
|
||||
return 'expense'
|
||||
}
|
||||
}
|
||||
|
||||
const form = reactive({
|
||||
name: '',
|
||||
type: BudgetPeriodType.Month,
|
||||
@@ -457,7 +579,6 @@ const handleDelete = (budget) => {
|
||||
const res = await deleteBudget(budget.id)
|
||||
if (res.success) {
|
||||
showToast('已删除')
|
||||
delete refDateMap[budget.id]
|
||||
fetchBudgetList()
|
||||
}
|
||||
} catch (err) {
|
||||
@@ -684,4 +805,70 @@ const onSubmit = async () => {
|
||||
:deep(.van-tabs__nav--card) {
|
||||
margin: 0 12px;
|
||||
}
|
||||
|
||||
.summary-card {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
padding: 12px 16px;
|
||||
margin-top: 12px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.summary-item {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.summary-item .label {
|
||||
font-size: 12px;
|
||||
color: #969799;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
.summary-item .value {
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 2px;
|
||||
color: #323233;
|
||||
}
|
||||
|
||||
.summary-item .value.expense {
|
||||
color: #ee0a24;
|
||||
}
|
||||
|
||||
.summary-item .value.income {
|
||||
color: #07c160;
|
||||
}
|
||||
|
||||
.summary-item .value.warning {
|
||||
color: #ff976a;
|
||||
}
|
||||
|
||||
.summary-item .unit {
|
||||
font-size: 11px;
|
||||
margin-left: 1px;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.summary-item .sub-label {
|
||||
font-size: 11px;
|
||||
color: #c8c9cc;
|
||||
}
|
||||
|
||||
.divider {
|
||||
width: 1px;
|
||||
height: 24px;
|
||||
background-color: #ebedf0;
|
||||
margin: 0 4px;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
.summary-item .value {
|
||||
color: #f5f5f5;
|
||||
}
|
||||
.divider {
|
||||
background-color: #2c2c2c;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user