This commit is contained in:
SunCheng
2026-02-15 10:10:28 +08:00
parent e51a3edd50
commit a88556c784
92 changed files with 6751 additions and 776 deletions

View File

@@ -1,127 +1,111 @@
<template>
<van-popup
<PopupContainer
v-model:show="visible"
position="bottom"
:style="{ height: '80%' }"
round
closeable
:title="title"
:subtitle="total > 0 ? `共 ${total} 笔交易` : ''"
:closeable="true"
>
<div class="popup-wrapper">
<!-- 头部 -->
<div class="popup-header">
<h2 class="popup-title">
{{ title }}
</h2>
<div
v-if="total > 0"
class="popup-subtitle"
>
{{ total }} 笔交易
<!-- 交易列表 -->
<div class="transactions">
<!-- 加载状态 -->
<van-loading
v-if="loading && transactions.length === 0"
class="txn-loading"
size="24px"
vertical
>
加载中...
</van-loading>
<!-- 空状态 -->
<div
v-else-if="transactions.length === 0"
class="txn-empty"
>
<div class="empty-icon">
<van-icon
name="balance-list-o"
size="48"
/>
</div>
<div class="empty-text">
暂无交易记录
</div>
</div>
<!-- 交易列表 -->
<div class="transactions">
<!-- 加载状态 -->
<van-loading
v-if="loading && transactions.length === 0"
class="txn-loading"
size="24px"
vertical
>
加载中...
</van-loading>
<!-- 空状态 -->
<div
v-else
class="txn-list"
>
<div
v-else-if="transactions.length === 0"
class="txn-empty"
v-for="txn in transactions"
:key="txn.id"
class="txn-card"
@click="onTransactionClick(txn)"
>
<div class="empty-icon">
<div
class="txn-icon"
:style="{ backgroundColor: txn.iconBg }"
>
<van-icon
name="balance-list-o"
size="48"
:name="txn.icon"
:color="txn.iconColor"
/>
</div>
<div class="empty-text">
暂无交易记录
<div class="txn-content">
<div class="txn-name">
{{ txn.reason }}
</div>
<div class="txn-footer">
<div class="txn-time">
{{ formatDateTime(txn.occurredAt) }}
</div>
<span
v-if="txn.classify"
class="txn-classify-tag"
:class="txn.type === 1 ? 'tag-income' : 'tag-expense'"
>
{{ txn.classify }}
</span>
</div>
</div>
<div class="txn-amount">
{{ formatAmount(txn.amount, txn.type) }}
</div>
</div>
<!-- 交易列表 -->
<!-- 加载更多 -->
<div
v-if="!finished"
class="load-more"
>
<van-loading
v-if="loading"
size="20px"
>
加载中...
</van-loading>
<van-button
v-else
type="primary"
size="small"
@click="loadMore"
>
加载更多
</van-button>
</div>
<!-- 已加载全部 -->
<div
v-else
class="txn-list"
class="finished-text"
>
<div
v-for="txn in transactions"
:key="txn.id"
class="txn-card"
@click="onTransactionClick(txn)"
>
<div
class="txn-icon"
:style="{ backgroundColor: txn.iconBg }"
>
<van-icon
:name="txn.icon"
:color="txn.iconColor"
/>
</div>
<div class="txn-content">
<div class="txn-name">
{{ txn.reason }}
</div>
<div class="txn-footer">
<div class="txn-time">
{{ formatDateTime(txn.occurredAt) }}
</div>
<span
v-if="txn.classify"
class="txn-classify-tag"
:class="txn.type === 1 ? 'tag-income' : 'tag-expense'"
>
{{ txn.classify }}
</span>
</div>
</div>
<div class="txn-amount">
{{ formatAmount(txn.amount, txn.type) }}
</div>
</div>
<!-- 加载更多 -->
<div
v-if="!finished"
class="load-more"
>
<van-loading
v-if="loading"
size="20px"
>
加载中...
</van-loading>
<van-button
v-else
type="primary"
size="small"
@click="loadMore"
>
加载更多
</van-button>
</div>
<!-- 已加载全部 -->
<div
v-else
class="finished-text"
>
已加载全部
</div>
已加载全部
</div>
</div>
</div>
</van-popup>
</PopupContainer>
<!-- 交易详情弹窗 -->
<TransactionDetailSheet
@@ -136,6 +120,7 @@
import { ref, computed, watch } from 'vue'
import { showToast } from 'vant'
import TransactionDetailSheet from '@/components/Transaction/TransactionDetailSheet.vue'
import PopupContainer from '@/components/PopupContainer.vue'
import { getTransactionList } from '@/api/transactionRecord'
const props = defineProps({
@@ -207,13 +192,13 @@ const formatAmount = (amount, type) => {
// 根据分类获取图标
const getIconByClassify = (classify) => {
const iconMap = {
'餐饮': 'food',
'购物': 'shopping',
'交通': 'logistics',
'娱乐': 'play-circle',
'医疗': 'medic',
'工资': 'gold-coin',
'红包': 'gift'
餐饮: 'food',
购物: 'shopping',
交通: 'logistics',
娱乐: 'play-circle',
医疗: 'medic',
工资: 'gold-coin',
红包: 'gift'
}
return iconMap[classify] || 'bill'
}
@@ -256,7 +241,7 @@ const loadData = async (isRefresh = false) => {
const newList = response.data || []
// 转换数据格式,添加显示所需的字段
const formattedList = newList.map(txn => ({
const formattedList = newList.map((txn) => ({
...txn,
icon: getIconByClassify(txn.classify),
iconColor: getColorByType(txn.type),
@@ -308,7 +293,7 @@ const handleSave = () => {
const handleDelete = (id) => {
showDetail.value = false
// 从列表中移除
transactions.value = transactions.value.filter(t => t.id !== id)
transactions.value = transactions.value.filter((t) => t.id !== id)
total.value--
// 通知父组件刷新
emit('refresh')
@@ -331,39 +316,6 @@ watch(visible, (newValue) => {
<style scoped>
@import '@/assets/theme.css';
.popup-wrapper {
height: 100%;
display: flex;
flex-direction: column;
background-color: var(--bg-primary);
}
.popup-header {
flex-shrink: 0;
padding: var(--spacing-2xl);
padding-bottom: var(--spacing-lg);
border-bottom: 1px solid var(--border-color);
background: var(--bg-secondary);
}
.popup-title {
font-family: var(--font-display);
font-size: var(--font-xl);
font-weight: var(--font-bold);
color: var(--text-primary);
margin: 0;
text-align: center;
letter-spacing: -0.02em;
}
.popup-subtitle {
margin-top: var(--spacing-sm);
font-size: var(--font-md);
font-weight: var(--font-medium);
color: var(--text-secondary);
text-align: center;
}
.transactions {
flex: 1;
overflow-y: auto;
@@ -452,7 +404,7 @@ watch(visible, (newValue) => {
.txn-classify-tag.tag-expense {
background-color: rgba(59, 130, 246, 0.15);
color: #3B82F6;
color: #3b82f6;
}
.txn-amount {