feat(frontend): 添加存款明细展示

- 在存款计划弹窗中添加详细明细表格
  - 收入明细列表(显示预算/实际/计算用金额)
  - 支出明细列表(显示超支标记)
  - 计算说明标签(使用预算/使用实际/超支/按天折算)

- 支持新旧版本兼容
  - 有 details 字段时显示详细明细
  - 无 details 字段时显示旧版汇总

- UI 优化
  - 超支项目红色边框高亮
  - 月度/年度标签区分
  - 计算汇总和公式展示
  - 移动端响应式布局
This commit is contained in:
SunCheng
2026-02-20 17:10:33 +08:00
parent 2cb5bffc70
commit f46b9d4bd6

View File

@@ -74,12 +74,168 @@
<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
v-if="currentBudget.details"
class="detail-tables"
>
<!-- 收入明细 -->
<div class="detail-section income-section">
<div class="section-title">
<van-icon name="balance-o" />
收入明细
</div>
<div class="detail-table">
<div
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
v-else
class="legacy-summary"
> >
<div class="detail-section income-section"> <div class="detail-section income-section">
<div class="section-title"> <div class="section-title">
@@ -169,6 +325,7 @@
</div> </div>
</div> </div>
</div> </div>
</div>
</PopupContainerV2> </PopupContainerV2>
</template> </template>
@@ -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>