<script setup> import { ref, onMounted } from 'vue' import { get } from "~/utils/request" definePageMeta({ layout: "default", title: "银行卡记录", name: "cardDetail", }) const route = useRoute() const bankList = ref([]) const loading = ref(true) const STATUS_CONFIG = { 0: { class: 'status-pending', text: '待打款', color: '#ff9800', icon: 'clock' }, 1: { class: 'status-processing', text: '提现中', color: '#2196f3', icon: 'loading' }, 2: { class: 'status-success', text: '已到账', color: '#4caf50', icon: 'check-circle' }, 3: { class: 'status-rejected', text: '驳回', color: '#f44336', icon: 'close-circle' } } const getStatusConfig = (status) => STATUS_CONFIG[status] || {} const formatTime = (time) => { if (!time) return '-' return new Date(time).toLocaleString('zh-CN', { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit' }) } const formatCardNumber = (number) => { if (!number) return '' return `**** ${number.slice(-4)}` } const formatAmount = (amount) => { if (!amount) return '0.00' return Number(amount).toFixed(2) } const fetchCardDetail = async () => { try { loading.value = true const res = await get('/ops/bankcard/list', { bankId: route.params.id }) if (res?.code === 200) { bankList.value = res.rows[0]?.xqxx?.oXq || [] } } catch (error) { console.error('获取记录失败:', error) showFailToast('加载失败,请重试') } finally { loading.value = false } } onMounted(fetchCardDetail) </script> <template> <div class="card-detail"> <var-loading description="加载中..." :loading="loading"> <transition-group name="list" tag="div" class="records-list"> <div v-for="(item, index) in bankList" :key="item.createTime || index" class="record-card"> <!-- 交易信息 --> <div class="transaction-info"> <div class="bank-info"> <var-icon name="bank" :size="24" /> <span class="bank-name">{{ item.bankName }}</span> <span class="card-number">{{ formatCardNumber(item.bankNum) }}</span> </div> <div class="amount" :class="getStatusConfig(item.status).class"> +{{ formatAmount(item.withdrawAmount) }} <span class="currency">元</span> </div> </div> <!-- 状态信息 --> <div class="status-info"> <div class="info-item"> <span class="label">申请时间</span> <span class="value">{{ formatTime(item.createTime) }}</span> </div> <div class="info-item"> <span class="label">当前状态</span> <span class="value status" :style="{ color: getStatusConfig(item.status).color }"> <var-icon :name="getStatusConfig(item.status).icon" :size="16" /> {{ getStatusConfig(item.status).text }} </span> </div> </div> <!-- 进度条 --> <div class="progress-track"> <var-steps :current="item.status" class="custom-steps"> <var-step>提交申请</var-step> <var-step>审核中</var-step> <var-step>审核通过</var-step> <var-step v-if="item.status === 3">驳回</var-step> </var-steps> </div> </div> </transition-group> <!-- 空状态 --> <div v-if="!loading && !bankList.length" class="empty-state"> <var-icon name="file-search" :size="64" color="#ccc" /> <p>暂无交易记录</p> </div> </var-loading> </div> </template> <style lang="scss" scoped> .card-detail { min-height: 100vh; background: #f5f7fa; padding: 16px; font-family: pingfang; } .records-list { display: flex; flex-direction: column; gap: 16px; } .record-card { background: white; border-radius: 12px; padding: 20px; box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08); transition: all 0.3s ease; &:hover { transform: translateY(-2px); box-shadow: 0 4px 20px rgba(0, 0, 0, 0.12); } .transaction-info { display: flex; justify-content: space-between; align-items: center; margin-bottom: 16px; padding-bottom: 16px; border-bottom: 1px solid #eee; .bank-info { display: flex; align-items: center; gap: 8px; .bank-name { font-size: 16px; font-weight: 500; color: #333; } .card-number { color: #666; font-size: 14px; } } .amount { font-size: 24px; font-weight: bold; .currency { font-size: 14px; margin-left: 4px; } &.status-pending { color: #ff9800; } &.status-processing { color: #2196f3; } &.status-success { color: #4caf50; } &.status-rejected { color: #f44336; } } } .status-info { display: flex; justify-content: space-between; margin-bottom: 20px; .info-item { .label { font-size: 14px; color: #666; margin-right: 8px; } .value { font-size: 14px; color: #333; &.status { display: flex; align-items: center; gap: 4px; font-weight: 500; } } } } .progress-track { margin-top: 24px; :deep(.custom-steps) { .var-step { &__content { font-size: 13px; } &__line { background: #e0e0e0; } &--finish { .var-step__line { background: #2196f3; } } } } } } .empty-state { height: 60vh; display: flex; flex-direction: column; justify-content: center; align-items: center; gap: 16px; p { color: #666; font-size: 16px; } } // 动画 .list-enter-active, .list-leave-active { transition: all 0.3s ease; } .list-enter-from { opacity: 0; transform: translateY(30px); } .list-leave-to { opacity: 0; transform: translateY(-30px); } .list-move { transition: transform 0.3s ease; } @keyframes spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } } .status-processing .var-icon { animation: spin 1.5s linear infinite; } </style>