All checks were successful
Docker Build & Deploy / Build Docker Image (push) Successful in 23s
Docker Build & Deploy / Deploy to Production (push) Successful in 6s
Docker Build & Deploy / Cleanup Dangling Images (push) Successful in 1s
Docker Build & Deploy / WeChat Notification (push) Successful in 1s
179 lines
3.9 KiB
Vue
179 lines
3.9 KiB
Vue
<template>
|
|
<div class="page-container-flex">
|
|
<!-- 自定义头部 -->
|
|
<header class="balance-header">
|
|
<h1 class="header-title">
|
|
账单
|
|
</h1>
|
|
<div class="header-actions">
|
|
<van-button
|
|
v-if="tabActive === 'email'"
|
|
size="small"
|
|
type="primary"
|
|
@click="emailRecordRef?.handleSync()"
|
|
>
|
|
立即同步
|
|
</van-button>
|
|
<van-icon
|
|
v-if="tabActive === 'message'"
|
|
name="passed"
|
|
size="20"
|
|
@click="messageViewRef?.handleMarkAllRead()"
|
|
/>
|
|
</div>
|
|
</header>
|
|
|
|
<!-- 分段控制器 -->
|
|
<div class="tabs-wrapper">
|
|
<div class="segmented-control">
|
|
<div
|
|
class="tab-item"
|
|
:class="{ active: tabActive === 'balance' }"
|
|
@click="tabActive = 'balance'"
|
|
>
|
|
<span class="tab-text">账单</span>
|
|
</div>
|
|
<div
|
|
class="tab-item"
|
|
:class="{ active: tabActive === 'email' }"
|
|
@click="tabActive = 'email'"
|
|
>
|
|
<span class="tab-text">邮件</span>
|
|
</div>
|
|
<div
|
|
class="tab-item"
|
|
:class="{ active: tabActive === 'message' }"
|
|
@click="tabActive = 'message'"
|
|
>
|
|
<span class="tab-text">消息</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<TransactionsRecord
|
|
v-if="tabActive === 'balance'"
|
|
ref="transactionsRecordRef"
|
|
/>
|
|
<EmailRecord
|
|
v-else-if="tabActive === 'email'"
|
|
ref="emailRecordRef"
|
|
/>
|
|
<MessageView
|
|
v-else-if="tabActive === 'message'"
|
|
ref="messageViewRef"
|
|
:is-component="true"
|
|
/>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { ref, watch } from 'vue'
|
|
import { useRoute } from 'vue-router'
|
|
import TransactionsRecord from './TransactionsRecord.vue'
|
|
import EmailRecord from './EmailRecord.vue'
|
|
import MessageView from './MessageView.vue'
|
|
|
|
const route = useRoute()
|
|
|
|
const tabActive = ref(route.query.tab || 'balance')
|
|
|
|
// 监听路由参数变化,用于从 tabbar 点击时切换 tab
|
|
watch(
|
|
() => route.query.tab,
|
|
(newTab) => {
|
|
if (newTab) {
|
|
tabActive.value = newTab
|
|
}
|
|
}
|
|
)
|
|
|
|
const transactionsRecordRef = ref(null)
|
|
const emailRecordRef = ref(null)
|
|
const messageViewRef = ref(null)
|
|
</script>
|
|
|
|
<style scoped lang="scss">
|
|
@import '@/assets/theme.css';
|
|
|
|
:deep(.van-pull-refresh) {
|
|
flex: 1;
|
|
overflow-y: auto;
|
|
-webkit-overflow-scrolling: touch;
|
|
}
|
|
|
|
/* ========== 自定义头部 ========== */
|
|
.balance-header {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
padding: 8px 24px;
|
|
background: transparent;
|
|
position: relative;
|
|
z-index: 1;
|
|
}
|
|
|
|
.header-title {
|
|
font-family: var(--font-primary);
|
|
font-size: var(--font-2xl);
|
|
font-weight: var(--font-medium);
|
|
color: var(--text-primary);
|
|
margin: 0;
|
|
}
|
|
|
|
.header-actions {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 12px;
|
|
}
|
|
|
|
/* ========== 分段控制器 ========== */
|
|
.tabs-wrapper {
|
|
padding: var(--spacing-sm) var(--spacing-xl);
|
|
}
|
|
|
|
.segmented-control {
|
|
display: flex;
|
|
background: var(--segmented-bg);
|
|
border-radius: 8px;
|
|
padding: 4px;
|
|
gap: 4px;
|
|
height: 40px;
|
|
}
|
|
|
|
.tab-item {
|
|
flex: 1;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
border-radius: 6px;
|
|
cursor: pointer;
|
|
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
|
background: transparent;
|
|
-webkit-tap-highlight-color: transparent;
|
|
user-select: none;
|
|
}
|
|
|
|
.tab-item.active {
|
|
background: var(--segmented-active-bg);
|
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.12);
|
|
}
|
|
|
|
.tab-item.active .tab-text {
|
|
color: var(--text-primary);
|
|
font-weight: var(--font-bold);
|
|
}
|
|
|
|
.tab-item:not(.active):hover {
|
|
background: rgba(128, 128, 128, 0.1);
|
|
}
|
|
|
|
.tab-text {
|
|
font-family: var(--font-primary);
|
|
font-size: var(--font-md);
|
|
font-weight: var(--font-medium);
|
|
color: var(--text-secondary);
|
|
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
|
user-select: none;
|
|
}
|
|
</style>
|