添加预算视图统计信息,显示本周、本月和年度达成率,优化样式和布局
This commit is contained in:
@@ -9,6 +9,31 @@
|
|||||||
<div class="page-content">
|
<div class="page-content">
|
||||||
<van-tabs v-model:active="activeTab" sticky offset-top="46" type="card">
|
<van-tabs v-model:active="activeTab" sticky offset-top="46" type="card">
|
||||||
<van-tab title="支出" :name="BudgetCategory.Expense">
|
<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">
|
<div class="budget-list">
|
||||||
<template v-if="expenseBudgets?.length > 0">
|
<template v-if="expenseBudgets?.length > 0">
|
||||||
<van-swipe-cell v-for="budget in expenseBudgets" :key="budget.id">
|
<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>
|
<van-tag v-else type="success" size="small" plain>进行中</van-tag>
|
||||||
</div>
|
</div>
|
||||||
<div class="header-actions">
|
<div class="header-actions">
|
||||||
<van-button icon="replay" size="mini" plain round @click="handleSync(budget)" :loading="budget.syncing" />
|
<van-button icon="replay" size="mini" plain @click="handleSync(budget)" :loading="budget.syncing" />
|
||||||
<van-button :icon="budget.isStopped ? 'play' : 'pause'" size="mini" plain round @click="handleToggleStop(budget)" />
|
<van-button :icon="budget.isStopped ? 'play' : 'pause'" size="mini" plain @click="handleToggleStop(budget)" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -78,6 +103,31 @@
|
|||||||
</van-tab>
|
</van-tab>
|
||||||
|
|
||||||
<van-tab title="收入" :name="BudgetCategory.Income">
|
<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">
|
<div class="budget-list">
|
||||||
<template v-if="incomeBudgets?.length > 0">
|
<template v-if="incomeBudgets?.length > 0">
|
||||||
<van-swipe-cell v-for="budget in incomeBudgets" :key="budget.id">
|
<van-swipe-cell v-for="budget in incomeBudgets" :key="budget.id">
|
||||||
@@ -147,6 +197,31 @@
|
|||||||
</van-tab>
|
</van-tab>
|
||||||
|
|
||||||
<van-tab title="存款" :name="BudgetCategory.Savings">
|
<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">
|
<div class="budget-list">
|
||||||
<template v-if="savingsBudgets?.length > 0">
|
<template v-if="savingsBudgets?.length > 0">
|
||||||
<van-swipe-cell v-for="budget in savingsBudgets" :key="budget.id">
|
<van-swipe-cell v-for="budget in savingsBudgets" :key="budget.id">
|
||||||
@@ -321,6 +396,53 @@ const expenseBudgets = ref([])
|
|||||||
const incomeBudgets = ref([])
|
const incomeBudgets = ref([])
|
||||||
const savingsBudgets = 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({
|
const form = reactive({
|
||||||
name: '',
|
name: '',
|
||||||
type: BudgetPeriodType.Month,
|
type: BudgetPeriodType.Month,
|
||||||
@@ -457,7 +579,6 @@ const handleDelete = (budget) => {
|
|||||||
const res = await deleteBudget(budget.id)
|
const res = await deleteBudget(budget.id)
|
||||||
if (res.success) {
|
if (res.success) {
|
||||||
showToast('已删除')
|
showToast('已删除')
|
||||||
delete refDateMap[budget.id]
|
|
||||||
fetchBudgetList()
|
fetchBudgetList()
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@@ -684,4 +805,70 @@ const onSubmit = async () => {
|
|||||||
:deep(.van-tabs__nav--card) {
|
:deep(.van-tabs__nav--card) {
|
||||||
margin: 0 12px;
|
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>
|
</style>
|
||||||
|
|||||||
Reference in New Issue
Block a user