196 lines
4.5 KiB
Vue
196 lines
4.5 KiB
Vue
<!--
|
||
CalendarV2 专用的交易列表组件
|
||
|
||
特殊功能:
|
||
- 自定义 header(Items 数量、Smart 按钮)
|
||
- 与日历视图紧密集成
|
||
- 使用统一的 BillListComponent 展示账单列表
|
||
|
||
迁移说明:已迁移至使用 BillListComponent,保留自定义 header 和 Smart 按钮
|
||
-->
|
||
<template>
|
||
<!-- 交易列表 -->
|
||
<div class="transactions">
|
||
<!-- 自定义 header (保留) -->
|
||
<div class="txn-header">
|
||
<h2 class="txn-title">
|
||
交易记录
|
||
</h2>
|
||
<div class="txn-actions">
|
||
<div class="txn-badge badge-success">
|
||
{{ transactionCount }} Items
|
||
</div>
|
||
<button
|
||
class="smart-btn"
|
||
@click="onSmartClick"
|
||
>
|
||
<van-icon name="fire" />
|
||
<span>Smart</span>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 统一的账单列表组件 -->
|
||
<BillListComponent
|
||
data-source="custom"
|
||
:transactions="transactions"
|
||
:loading="transactionsLoading"
|
||
:finished="true"
|
||
:show-delete="true"
|
||
:enable-filter="false"
|
||
@click="onTransactionClick"
|
||
@delete="onTransactionDelete"
|
||
/>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { computed, watch, ref } from 'vue'
|
||
import { getTransactionsByDate } from '@/api/transactionRecord'
|
||
import BillListComponent from '@/components/Bill/BillListComponent.vue'
|
||
|
||
const props = defineProps({
|
||
selectedDate: Date
|
||
})
|
||
|
||
const emit = defineEmits(['transactionClick', 'smartClick'])
|
||
|
||
// 组件内部数据
|
||
const transactions = ref([])
|
||
const transactionsLoading = ref(false)
|
||
|
||
// 格式化日期为 key (yyyy-MM-dd)
|
||
const formatDateKey = (date) => {
|
||
const year = date.getFullYear()
|
||
const month = String(date.getMonth() + 1).padStart(2, '0')
|
||
const day = String(date.getDate()).padStart(2, '0')
|
||
return `${year}-${month}-${day}`
|
||
}
|
||
|
||
// 获取选中日期的交易列表
|
||
const fetchDayTransactions = async (date) => {
|
||
try {
|
||
transactionsLoading.value = true
|
||
const dateKey = formatDateKey(date)
|
||
const response = await getTransactionsByDate(dateKey)
|
||
|
||
if (response.success && response.data) {
|
||
// 直接使用原始数据,交给 BillListComponent 处理格式化
|
||
transactions.value = response.data
|
||
}
|
||
} catch (error) {
|
||
console.error('获取交易记录失败:', error)
|
||
} finally {
|
||
transactionsLoading.value = false
|
||
}
|
||
}
|
||
|
||
// 监听 selectedDate 变化,重新加载数据
|
||
watch(
|
||
() => props.selectedDate,
|
||
async (newDate) => {
|
||
if (newDate) {
|
||
await fetchDayTransactions(newDate)
|
||
}
|
||
},
|
||
{ immediate: true }
|
||
)
|
||
|
||
// 交易数量
|
||
const transactionCount = computed(() => transactions.value.length)
|
||
|
||
// 点击交易卡片
|
||
const onTransactionClick = (txn) => {
|
||
emit('transactionClick', txn)
|
||
}
|
||
|
||
// 删除交易后的处理
|
||
const onTransactionDelete = (deletedId) => {
|
||
// BillListComponent 已经完成删除 API 调用
|
||
// 这里只需要从本地列表中移除该项
|
||
transactions.value = transactions.value.filter((t) => t.id !== deletedId)
|
||
}
|
||
|
||
// 点击 Smart 按钮
|
||
const onSmartClick = () => {
|
||
emit('smartClick')
|
||
}
|
||
</script>
|
||
|
||
<style scoped>
|
||
@import '@/assets/theme.css';
|
||
|
||
/* ========== 交易列表容器 ========== */
|
||
.transactions {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: var(--spacing-lg);
|
||
padding: var(--spacing-xl, 16px);
|
||
padding-top: 0;
|
||
}
|
||
|
||
/* 移除 BillListComponent 内部的左右 padding/margin */
|
||
:deep(.van-cell-group) {
|
||
margin-left: 0 !important;
|
||
margin-right: 0 !important;
|
||
}
|
||
|
||
:deep(.van-list) {
|
||
padding-left: 0 !important;
|
||
padding-right: 0 !important;
|
||
}
|
||
|
||
/* ========== 自定义 Header (保留) ========== */
|
||
.txn-header {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
}
|
||
|
||
.txn-title {
|
||
font-family: var(--font-display);
|
||
font-size: var(--font-xl);
|
||
font-weight: var(--font-bold);
|
||
color: var(--text-primary);
|
||
margin: 0;
|
||
}
|
||
|
||
.txn-actions {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: var(--spacing-md);
|
||
}
|
||
|
||
.txn-badge {
|
||
padding: 6px 12px;
|
||
font-size: var(--font-base);
|
||
font-weight: var(--font-semibold);
|
||
border-radius: var(--radius-sm);
|
||
}
|
||
|
||
.badge-success {
|
||
background-color: var(--accent-success-bg);
|
||
color: var(--accent-success);
|
||
}
|
||
|
||
.smart-btn {
|
||
display: flex;
|
||
align-items: center;
|
||
margin-left: 6px;
|
||
gap: 6px;
|
||
padding: 6px 12px;
|
||
background-color: var(--accent-info-bg);
|
||
color: var(--accent-info);
|
||
border: none;
|
||
border-radius: var(--radius-sm);
|
||
font-size: var(--font-base);
|
||
font-weight: var(--font-semibold);
|
||
cursor: pointer;
|
||
transition: opacity 0.2s;
|
||
}
|
||
|
||
.smart-btn:active {
|
||
opacity: 0.7;
|
||
}
|
||
</style>
|