feat(frontend): 添加存款明细展示
- 在存款计划弹窗中添加详细明细表格 - 收入明细列表(显示预算/实际/计算用金额) - 支出明细列表(显示超支标记) - 计算说明标签(使用预算/使用实际/超支/按天折算) - 支持新旧版本兼容 - 有 details 字段时显示详细明细 - 无 details 字段时显示旧版汇总 - UI 优化 - 超支项目红色边框高亮 - 月度/年度标签区分 - 计算汇总和公式展示 - 移动端响应式布局
This commit is contained in:
@@ -74,96 +74,253 @@
|
|||||||
<PopupContainerV2
|
<PopupContainerV2
|
||||||
v-model:show="showDetailPopup"
|
v-model:show="showDetailPopup"
|
||||||
title="计划存款明细"
|
title="计划存款明细"
|
||||||
:height="'80%'"
|
:height="'85%'"
|
||||||
>
|
>
|
||||||
<div class="popup-body">
|
<div class="popup-body">
|
||||||
<div
|
<div
|
||||||
v-if="currentBudget"
|
v-if="currentBudget"
|
||||||
class="detail-content"
|
class="detail-content"
|
||||||
>
|
>
|
||||||
<div class="detail-section income-section">
|
<!-- 明细表格 -->
|
||||||
<div class="section-title">
|
<div
|
||||||
<van-icon name="balance-o" />
|
v-if="currentBudget.details"
|
||||||
收入预算
|
class="detail-tables"
|
||||||
</div>
|
>
|
||||||
<div class="section-content">
|
<!-- 收入明细 -->
|
||||||
<div class="detail-row">
|
<div class="detail-section income-section">
|
||||||
<span class="detail-label">预算限额</span>
|
<div class="section-title">
|
||||||
<span class="detail-value income">¥{{ formatMoney(incomeLimit) }}</span>
|
<van-icon name="balance-o" />
|
||||||
|
收入明细
|
||||||
</div>
|
</div>
|
||||||
<div class="detail-row">
|
<div class="detail-table">
|
||||||
<span class="detail-label">实际收入</span>
|
<div
|
||||||
<span class="detail-value">¥{{ formatMoney(incomeCurrent) }}</span>
|
v-for="item in currentBudget.details.incomeItems"
|
||||||
|
:key="item.id"
|
||||||
|
class="detail-item"
|
||||||
|
>
|
||||||
|
<div class="item-header">
|
||||||
|
<span class="item-name">{{ item.name }}</span>
|
||||||
|
<van-tag
|
||||||
|
size="mini"
|
||||||
|
:type="item.type === 1 ? 'default' : 'primary'"
|
||||||
|
>
|
||||||
|
{{ item.type === 1 ? '月度' : '年度' }}
|
||||||
|
</van-tag>
|
||||||
|
</div>
|
||||||
|
<div class="item-amounts">
|
||||||
|
<div class="amount-row">
|
||||||
|
<span class="amount-label">预算</span>
|
||||||
|
<span class="amount-value">¥{{ formatMoney(item.budgetLimit) }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="amount-row">
|
||||||
|
<span class="amount-label">实际</span>
|
||||||
|
<span
|
||||||
|
class="amount-value"
|
||||||
|
:class="{ warning: item.isOverBudget }"
|
||||||
|
>
|
||||||
|
¥{{ formatMoney(item.actualAmount) }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="amount-row highlight">
|
||||||
|
<span class="amount-label">计算用</span>
|
||||||
|
<span class="amount-value income">¥{{ formatMoney(item.effectiveAmount) }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="item-note">
|
||||||
|
<van-tag
|
||||||
|
size="mini"
|
||||||
|
plain
|
||||||
|
:type="item.isOverBudget ? 'warning' : 'success'"
|
||||||
|
>
|
||||||
|
{{ item.calculationNote }}
|
||||||
|
</van-tag>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 支出明细 -->
|
||||||
|
<div class="detail-section expense-section">
|
||||||
|
<div class="section-title">
|
||||||
|
<van-icon name="bill-o" />
|
||||||
|
支出明细
|
||||||
|
</div>
|
||||||
|
<div class="detail-table">
|
||||||
|
<div
|
||||||
|
v-for="item in currentBudget.details.expenseItems"
|
||||||
|
:key="item.id"
|
||||||
|
class="detail-item"
|
||||||
|
:class="{ overbudget: item.isOverBudget }"
|
||||||
|
>
|
||||||
|
<div class="item-header">
|
||||||
|
<span class="item-name">{{ item.name }}</span>
|
||||||
|
<van-tag
|
||||||
|
size="mini"
|
||||||
|
:type="item.type === 1 ? 'default' : 'primary'"
|
||||||
|
>
|
||||||
|
{{ item.type === 1 ? '月度' : '年度' }}
|
||||||
|
</van-tag>
|
||||||
|
</div>
|
||||||
|
<div class="item-amounts">
|
||||||
|
<div class="amount-row">
|
||||||
|
<span class="amount-label">预算</span>
|
||||||
|
<span class="amount-value">¥{{ formatMoney(item.budgetLimit) }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="amount-row">
|
||||||
|
<span class="amount-label">实际</span>
|
||||||
|
<span
|
||||||
|
class="amount-value"
|
||||||
|
:class="{ danger: item.isOverBudget }"
|
||||||
|
>
|
||||||
|
¥{{ formatMoney(item.actualAmount) }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="amount-row highlight">
|
||||||
|
<span class="amount-label">计算用</span>
|
||||||
|
<span class="amount-value expense">¥{{ formatMoney(item.effectiveAmount) }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="item-note">
|
||||||
|
<van-tag
|
||||||
|
size="mini"
|
||||||
|
plain
|
||||||
|
:type="item.isOverBudget ? 'danger' : 'default'"
|
||||||
|
>
|
||||||
|
{{ item.calculationNote }}
|
||||||
|
</van-tag>
|
||||||
|
<van-tag
|
||||||
|
v-if="item.isOverBudget"
|
||||||
|
size="mini"
|
||||||
|
type="danger"
|
||||||
|
>
|
||||||
|
超支
|
||||||
|
</van-tag>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 计算汇总 -->
|
||||||
|
<div class="detail-section formula-section">
|
||||||
|
<div class="section-title">
|
||||||
|
<van-icon name="calculator-o" />
|
||||||
|
计算汇总
|
||||||
|
</div>
|
||||||
|
<div class="formula-box">
|
||||||
|
<div class="formula-row">
|
||||||
|
<span class="formula-label">收入合计</span>
|
||||||
|
<span class="formula-value income">
|
||||||
|
¥{{ formatMoney(currentBudget.details.summary.totalIncomeBudget) }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="formula-row">
|
||||||
|
<span class="formula-label">支出合计</span>
|
||||||
|
<span class="formula-value expense">
|
||||||
|
¥{{ formatMoney(currentBudget.details.summary.totalExpenseBudget) }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="formula-row highlight">
|
||||||
|
<span class="formula-label">计划存款</span>
|
||||||
|
<span class="formula-value primary">
|
||||||
|
¥{{ formatMoney(currentBudget.details.summary.plannedSavings) }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="formula-text">
|
||||||
|
{{ currentBudget.details.summary.calculationFormula }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="detail-section expense-section">
|
<!-- 旧版汇总(无明细数据时显示) -->
|
||||||
<div class="section-title">
|
<div
|
||||||
<van-icon name="bill-o" />
|
v-else
|
||||||
支出预算
|
class="legacy-summary"
|
||||||
</div>
|
>
|
||||||
<div class="section-content">
|
<div class="detail-section income-section">
|
||||||
<div class="detail-row">
|
<div class="section-title">
|
||||||
<span class="detail-label">预算限额</span>
|
<van-icon name="balance-o" />
|
||||||
<span class="detail-value expense">¥{{ formatMoney(expenseLimit) }}</span>
|
收入预算
|
||||||
</div>
|
</div>
|
||||||
<div class="detail-row">
|
<div class="section-content">
|
||||||
<span class="detail-label">实际支出</span>
|
<div class="detail-row">
|
||||||
<span class="detail-value">¥{{ formatMoney(expenseCurrent) }}</span>
|
<span class="detail-label">预算限额</span>
|
||||||
|
<span class="detail-value income">¥{{ formatMoney(incomeLimit) }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="detail-row">
|
||||||
|
<span class="detail-label">实际收入</span>
|
||||||
|
<span class="detail-value">¥{{ formatMoney(incomeCurrent) }}</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="detail-section formula-section">
|
<div class="detail-section expense-section">
|
||||||
<div class="section-title">
|
<div class="section-title">
|
||||||
<van-icon name="calculator-o" />
|
<van-icon name="bill-o" />
|
||||||
计划存款公式
|
支出预算
|
||||||
</div>
|
|
||||||
<div class="formula-box">
|
|
||||||
<div class="formula-item">
|
|
||||||
<span class="formula-label">收入预算</span>
|
|
||||||
<span class="formula-value income">¥{{ formatMoney(incomeLimit) }}</span>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="formula-operator">
|
<div class="section-content">
|
||||||
-
|
<div class="detail-row">
|
||||||
</div>
|
<span class="detail-label">预算限额</span>
|
||||||
<div class="formula-item">
|
<span class="detail-value expense">¥{{ formatMoney(expenseLimit) }}</span>
|
||||||
<span class="formula-label">支出预算</span>
|
</div>
|
||||||
<span class="formula-value expense">¥{{ formatMoney(expenseLimit) }}</span>
|
<div class="detail-row">
|
||||||
</div>
|
<span class="detail-label">实际支出</span>
|
||||||
<div class="formula-operator">
|
<span class="detail-value">¥{{ formatMoney(expenseCurrent) }}</span>
|
||||||
=
|
</div>
|
||||||
</div>
|
|
||||||
<div class="formula-item">
|
|
||||||
<span class="formula-label">计划存款</span>
|
|
||||||
<span class="formula-value">¥{{ formatMoney(currentBudget.limit) }}</span>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="detail-section result-section">
|
<div class="detail-section formula-section">
|
||||||
<div class="section-title">
|
<div class="section-title">
|
||||||
<van-icon name="chart-trending-o" />
|
<van-icon name="calculator-o" />
|
||||||
存款结果
|
计划存款公式
|
||||||
|
</div>
|
||||||
|
<div class="formula-box">
|
||||||
|
<div class="formula-item">
|
||||||
|
<span class="formula-label">收入预算</span>
|
||||||
|
<span class="formula-value income">¥{{ formatMoney(incomeLimit) }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="formula-operator">
|
||||||
|
-
|
||||||
|
</div>
|
||||||
|
<div class="formula-item">
|
||||||
|
<span class="formula-label">支出预算</span>
|
||||||
|
<span class="formula-value expense">¥{{ formatMoney(expenseLimit) }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="formula-operator">
|
||||||
|
=
|
||||||
|
</div>
|
||||||
|
<div class="formula-item">
|
||||||
|
<span class="formula-label">计划存款</span>
|
||||||
|
<span class="formula-value">¥{{ formatMoney(currentBudget.limit) }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="section-content">
|
|
||||||
<div class="detail-row">
|
<div class="detail-section result-section">
|
||||||
<span class="detail-label">计划存款</span>
|
<div class="section-title">
|
||||||
<span class="detail-value">¥{{ formatMoney(currentBudget.limit) }}</span>
|
<van-icon name="chart-trending-o" />
|
||||||
|
存款结果
|
||||||
</div>
|
</div>
|
||||||
<div class="detail-row">
|
<div class="section-content">
|
||||||
<span class="detail-label">实际存款</span>
|
<div class="detail-row">
|
||||||
<span
|
<span class="detail-label">计划存款</span>
|
||||||
class="detail-value"
|
<span class="detail-value">¥{{ formatMoney(currentBudget.limit) }}</span>
|
||||||
:class="{ income: currentBudget.current >= currentBudget.limit }"
|
</div>
|
||||||
>¥{{ formatMoney(currentBudget.current) }}</span>
|
<div class="detail-row">
|
||||||
</div>
|
<span class="detail-label">实际存款</span>
|
||||||
<div class="detail-row highlight">
|
<span
|
||||||
<span class="detail-label">还差</span>
|
class="detail-value"
|
||||||
<span class="detail-value expense">¥{{
|
:class="{ income: currentBudget.current >= currentBudget.limit }"
|
||||||
formatMoney(Math.max(0, currentBudget.limit - currentBudget.current))
|
>¥{{ formatMoney(currentBudget.current) }}</span>
|
||||||
}}</span>
|
</div>
|
||||||
|
<div class="detail-row highlight">
|
||||||
|
<span class="detail-label">还差</span>
|
||||||
|
<span class="detail-value expense">¥{{
|
||||||
|
formatMoney(Math.max(0, currentBudget.limit - currentBudget.current))
|
||||||
|
}}</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -477,4 +634,128 @@ const getProgressColor = (budget) => {
|
|||||||
color: var(--van-text-color-2);
|
color: var(--van-text-color-2);
|
||||||
padding: 0 8px;
|
padding: 0 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 明细表格样式 */
|
||||||
|
.detail-tables {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-table {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-item {
|
||||||
|
background-color: var(--van-light-gray);
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 12px;
|
||||||
|
border-left: 3px solid var(--van-gray-4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-item.overbudget {
|
||||||
|
border-left-color: var(--van-danger-color);
|
||||||
|
background-color: rgba(245, 34, 45, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-name {
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--van-text-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-amounts {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 6px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.amount-row {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.amount-row.highlight {
|
||||||
|
padding-top: 6px;
|
||||||
|
margin-top: 4px;
|
||||||
|
border-top: 1px dashed var(--van-border-color);
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.amount-label {
|
||||||
|
color: var(--van-text-color-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.amount-value {
|
||||||
|
font-family: DIN Alternate, system-ui;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--van-text-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.amount-value.income {
|
||||||
|
color: var(--van-success-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.amount-value.expense {
|
||||||
|
color: var(--van-danger-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.amount-value.warning {
|
||||||
|
color: var(--van-warning-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.amount-value.danger {
|
||||||
|
color: var(--van-danger-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-note {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.formula-row {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 8px 0;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.formula-row.highlight {
|
||||||
|
margin-top: 8px;
|
||||||
|
padding-top: 12px;
|
||||||
|
border-top: 2px solid var(--van-border-color);
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.formula-value.primary {
|
||||||
|
color: var(--van-primary-color);
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.formula-text {
|
||||||
|
margin-top: 12px;
|
||||||
|
padding: 10px;
|
||||||
|
background-color: var(--van-light-gray);
|
||||||
|
border-radius: 6px;
|
||||||
|
font-size: 13px;
|
||||||
|
color: var(--van-text-color-2);
|
||||||
|
text-align: center;
|
||||||
|
font-family: DIN Alternate, system-ui;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
Reference in New Issue
Block a user