986 lines
20 KiB
Plaintext
986 lines
20 KiB
Plaintext
<!-- 閽卞寘椤甸潰 -->
|
|
<template>
|
|
<view class="wallet-page">
|
|
<!-- 椤堕儴鏍?-->
|
|
<!--<view class="wallet-header">
|
|
<text class="back-btn" @click="goBack">鈥?/text>
|
|
</view>-->
|
|
|
|
<scroll-view class="wallet-content" scroll-y>
|
|
<!-- 浣欓姒傝 -->
|
|
<view class="balance-overview">
|
|
<text class="balance-label">璐︽埛浣欓</text>
|
|
<text class="balance-value">楼{{ balance.toFixed(2) }}</text>
|
|
<view class="balance-actions">
|
|
<button class="action-btn recharge" @click="recharge">鍏呭€?/button>
|
|
<button class="action-btn withdraw" @click="withdraw">鎻愮幇</button>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 璧勪骇缁熻 -->
|
|
<view class="assets-stats">
|
|
<view class="stat-item">
|
|
<text class="stat-label">绱鍏呭€?/text>
|
|
<text class="stat-value">楼{{ stats.totalRecharge.toFixed(2) }}</text>
|
|
</view>
|
|
<view class="stat-item">
|
|
<text class="stat-label">绱娑堣垂</text>
|
|
<text class="stat-value">楼{{ stats.totalConsume.toFixed(2) }}</text>
|
|
</view>
|
|
<view class="stat-item">
|
|
<text class="stat-label">绱鎻愮幇</text>
|
|
<text class="stat-value">楼{{ stats.totalWithdraw.toFixed(2) }}</text>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 蹇嵎鍔熻兘 -->
|
|
<view class="quick-actions">
|
|
<view class="action-grid">
|
|
<view class="action-item" @click="goToCoupons">
|
|
<text class="action-icon">馃帿</text>
|
|
<text class="action-text">浼樻儬鍒?/text>
|
|
</view>
|
|
<view class="action-item" @click="goToRedPackets">
|
|
<text class="action-icon">馃Ё</text>
|
|
<text class="action-text">绾㈠寘</text>
|
|
</view>
|
|
<view class="action-item" @click="goToPoints">
|
|
<text class="action-icon">猸?/text>
|
|
<text class="action-text">绉垎</text>
|
|
</view>
|
|
<view class="action-item" @click="goToBankCards">
|
|
<text class="action-icon">馃挸</text>
|
|
<text class="action-text">閾惰鍗?/text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 浜ゆ槗璁板綍 -->
|
|
<view class="transactions-section">
|
|
<view class="section-header">
|
|
<text class="section-title">浜ゆ槗璁板綍</text>
|
|
<view class="filter-tabs">
|
|
<text :class="['filter-tab', { active: activeFilter === 'all' }]"
|
|
@click="changeFilter('all')">鍏ㄩ儴</text>
|
|
<text :class="['filter-tab', { active: activeFilter === 'income' }]"
|
|
@click="changeFilter('income')">鏀跺叆</text>
|
|
<text :class="['filter-tab', { active: activeFilter === 'expense' }]"
|
|
@click="changeFilter('expense')">鏀嚭</text>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 绌虹姸鎬?-->
|
|
<view v-if="transactions.length === 0 && !isLoading" class="empty-transactions">
|
|
<text class="empty-icon">馃挵</text>
|
|
<text class="empty-text">鏆傛棤浜ゆ槗璁板綍</text>
|
|
<text class="empty-subtext">蹇幓浣跨敤閽卞寘鍔熻兘鍚?/text>
|
|
</view>
|
|
|
|
<!-- 浜ゆ槗鍒楄〃 -->
|
|
<view class="transactions-list">
|
|
<view v-for="transaction in transactions"
|
|
:key="transaction.id"
|
|
class="transaction-item">
|
|
<view class="transaction-left">
|
|
<text class="transaction-icon">{{ getTransactionIcon(transaction.type) }}</text>
|
|
<view class="transaction-info">
|
|
<text class="transaction-title">{{ getTransactionTitle(transaction.type) }}</text>
|
|
<text class="transaction-time">{{ formatTime(transaction.created_at) }}</text>
|
|
<text v-if="transaction.remark" class="transaction-remark">{{ transaction.remark }}</text>
|
|
</view>
|
|
</view>
|
|
<view class="transaction-right">
|
|
<text :class="['transaction-amount',
|
|
{ income: transaction.amount > 0, expense: transaction.amount < 0 }]">
|
|
{{ transaction.amount > 0 ? '+' : '' }}楼{{ Math.abs(transaction.amount).toFixed(2) }}
|
|
</text>
|
|
<text class="transaction-balance">浣欓: 楼{{ transaction.current_balance.toFixed(2) }}</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 鍔犺浇鏇村 -->
|
|
<view v-if="isLoading" class="loading-more">
|
|
<text class="loading-text">鍔犺浇涓?..</text>
|
|
</view>
|
|
<view v-if="!hasMore && transactions.length > 0" class="no-more">
|
|
<text class="no-more-text">娌℃湁鏇村璁板綍浜?/text>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 瀹夊叏鎻愮ず -->
|
|
<view class="security-tips">
|
|
<text class="tip-title">瀹夊叏鎻愮ず</text>
|
|
<text class="tip-item">1. 璇峰Ε鍠勪繚绠℃偍鐨勬敮浠樺瘑鐮?/text>
|
|
<text class="tip-item">2. 涓嶈鍚戜粬浜洪€忛湶鎮ㄧ殑璐︽埛淇℃伅</text>
|
|
<text class="tip-item">3. 瀹氭湡淇敼瀵嗙爜浠ョ‘淇濊处鎴峰畨鍏?/text>
|
|
</view>
|
|
</scroll-view>
|
|
|
|
<!-- 鍏呭€煎脊绐?-->
|
|
<view v-if="showRechargePopup" class="recharge-popup">
|
|
<view class="popup-mask" @click="closeRechargePopup"></view>
|
|
<view class="popup-content">
|
|
<view class="popup-header">
|
|
<text class="popup-title">鍏呭€?/text>
|
|
<text class="popup-close" @click="closeRechargePopup">脳</text>
|
|
</view>
|
|
<view class="popup-body">
|
|
<text class="amount-label">鍏呭€奸噾棰?/text>
|
|
<view class="amount-input">
|
|
<text class="currency-symbol">楼</text>
|
|
<input class="amount-field"
|
|
v-model="rechargeAmount"
|
|
type="number"
|
|
placeholder="璇疯緭鍏ュ厖鍊奸噾棰?
|
|
focus />
|
|
</view>
|
|
<view class="quick-amounts">
|
|
<text v-for="amount in quickAmounts"
|
|
:key="amount"
|
|
:class="['quick-amount', { active: rechargeAmount === amount.toString() }]"
|
|
@click="selectQuickAmount(amount)">
|
|
楼{{ amount }}
|
|
</text>
|
|
</view>
|
|
<text class="recharge-tip">鍗曠瑪鍏呭€兼渶浣?0鍏冿紝鏈€楂?000鍏?/text>
|
|
</view>
|
|
<view class="popup-footer">
|
|
<button class="cancel-btn" @click="closeRechargePopup">鍙栨秷</button>
|
|
<button class="confirm-btn"
|
|
:class="{ disabled: !canRecharge }"
|
|
@click="confirmRecharge">
|
|
纭鍏呭€?
|
|
</button>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</template>
|
|
|
|
<script setup lang="uts">
|
|
import { ref, onMounted, computed, watch } from 'vue'
|
|
//import supa from '@/components/supadb/aksupainstance.uts'
|
|
|
|
type WalletType = {
|
|
id: string
|
|
user_id: string
|
|
balance: number
|
|
total_recharge: number
|
|
total_consume: number
|
|
total_withdraw: number
|
|
updated_at: string
|
|
}
|
|
|
|
type TransactionType = {
|
|
id: string
|
|
user_id: string
|
|
change_amount: number
|
|
current_balance: number
|
|
change_type: string // 'recharge' | 'consume' | 'withdraw' | 'refund' | 'reward'
|
|
related_id: string | null
|
|
remark: string | null
|
|
created_at: string
|
|
}
|
|
|
|
type StatsType = {
|
|
totalRecharge: number
|
|
totalConsume: number
|
|
totalWithdraw: number
|
|
}
|
|
|
|
const balance = ref<number>(0)
|
|
const stats = ref<StatsType>({
|
|
totalRecharge: 0,
|
|
totalConsume: 0,
|
|
totalWithdraw: 0
|
|
})
|
|
const transactions = ref<Array<TransactionType>>([])
|
|
const activeFilter = ref<string>('all')
|
|
const isLoading = ref<boolean>(false)
|
|
const currentPage = ref<number>(1)
|
|
const pageSize = ref<number>(20)
|
|
const hasMore = ref<boolean>(true)
|
|
const showRechargePopup = ref<boolean>(false)
|
|
const rechargeAmount = ref<string>('')
|
|
const quickAmounts = [50, 100, 200, 500, 1000]
|
|
|
|
// 璁$畻灞炴€?
|
|
const canRecharge = computed(() => {
|
|
const amount = parseFloat(rechargeAmount.value)
|
|
return !isNaN(amount) && amount >= 10 && amount <= 5000
|
|
})
|
|
|
|
// 鐩戝惉杩囨护鍣ㄥ彉鍖?
|
|
watch(activeFilter, () => {
|
|
resetTransactions()
|
|
loadTransactions()
|
|
})
|
|
|
|
// 鐢熷懡鍛ㄦ湡
|
|
onMounted(() => {
|
|
loadWalletData()
|
|
})
|
|
|
|
// 閲嶇疆浜ゆ槗璁板綍
|
|
const resetTransactions = () => {
|
|
transactions.value = []
|
|
currentPage.value = 1
|
|
hasMore.value = true
|
|
}
|
|
|
|
// 鍔犺浇閽卞寘鏁版嵁
|
|
const loadWalletData = async () => {
|
|
const userId = getCurrentUserId()
|
|
if (!userId) {
|
|
uni.navigateTo({
|
|
url: '/pages/user/login'
|
|
})
|
|
return
|
|
}
|
|
|
|
await Promise.all([
|
|
loadBalance(),
|
|
loadTransactions()
|
|
])
|
|
}
|
|
|
|
// 鍔犺浇浣欓淇℃伅
|
|
const loadBalance = async () => {
|
|
const userId = getCurrentUserId()
|
|
if (!userId) return
|
|
|
|
try {
|
|
const { data, error } = await supa
|
|
.from('user_wallets')
|
|
.select('*')
|
|
.eq('user_id', userId)
|
|
.single()
|
|
|
|
if (error !== null) {
|
|
console.error('鍔犺浇閽卞寘澶辫触:', error)
|
|
return
|
|
}
|
|
|
|
if (data) {
|
|
balance.value = data.balance || 0
|
|
stats.value = {
|
|
totalRecharge: data.total_recharge || 0,
|
|
totalConsume: data.total_consume || 0,
|
|
totalWithdraw: data.total_withdraw || 0
|
|
}
|
|
}
|
|
} catch (err) {
|
|
console.error('鍔犺浇閽卞寘寮傚父:', err)
|
|
}
|
|
}
|
|
|
|
// 鍔犺浇浜ゆ槗璁板綍
|
|
const loadTransactions = async (loadMore: boolean = false) => {
|
|
if (isLoading.value || (!hasMore.value && loadMore)) {
|
|
return
|
|
}
|
|
|
|
isLoading.value = true
|
|
|
|
try {
|
|
const userId = getCurrentUserId()
|
|
if (!userId) return
|
|
|
|
const page = loadMore ? currentPage.value + 1 : 1
|
|
|
|
let query = supa
|
|
.from('balance_records')
|
|
.select('*')
|
|
.eq('user_id', userId)
|
|
.order('created_at', { ascending: false })
|
|
|
|
// 鏍规嵁杩囨护鍣ㄧ瓫閫?
|
|
if (activeFilter.value === 'income') {
|
|
query = query.gt('change_amount', 0)
|
|
} else if (activeFilter.value === 'expense') {
|
|
query = query.lt('change_amount', 0)
|
|
}
|
|
|
|
// 鍒嗛〉
|
|
query = query.range((page - 1) * pageSize.value, page * pageSize.value - 1)
|
|
|
|
const { data, error } = await query
|
|
|
|
if (error !== null) {
|
|
console.error('鍔犺浇浜ゆ槗璁板綍澶辫触:', error)
|
|
return
|
|
}
|
|
|
|
const newTransactions = data || []
|
|
|
|
if (loadMore) {
|
|
transactions.value.push(...newTransactions)
|
|
currentPage.value = page
|
|
} else {
|
|
transactions.value = newTransactions
|
|
currentPage.value = 1
|
|
}
|
|
|
|
hasMore.value = newTransactions.length === pageSize.value
|
|
} catch (err) {
|
|
console.error('鍔犺浇浜ゆ槗璁板綍寮傚父:', err)
|
|
} finally {
|
|
isLoading.value = false
|
|
}
|
|
}
|
|
|
|
// 鑾峰彇褰撳墠鐢ㄦ埛ID
|
|
const getCurrentUserId = (): string => {
|
|
const userStore = uni.getStorageSync('userInfo')
|
|
return userStore?.id || ''
|
|
}
|
|
|
|
// 鑾峰彇浜ゆ槗鍥炬爣
|
|
const getTransactionIcon = (type: string): string => {
|
|
const icons: Record<string, string> = {
|
|
recharge: '馃挸',
|
|
consume: '馃洅',
|
|
withdraw: '馃彟',
|
|
refund: '馃攧',
|
|
reward: '馃巵',
|
|
income: '馃挵',
|
|
expense: '馃摛'
|
|
}
|
|
return icons[type] || '馃挵'
|
|
}
|
|
|
|
// 鑾峰彇浜ゆ槗鏍囬
|
|
const getTransactionTitle = (type: string): string => {
|
|
const titles: Record<string, string> = {
|
|
recharge: '璐︽埛鍏呭€?,
|
|
consume: '鍟嗗搧娑堣垂',
|
|
withdraw: '浣欓鎻愮幇',
|
|
refund: '璁㈠崟閫€娆?,
|
|
reward: '娲诲姩濂栧姳',
|
|
income: '鏀跺叆',
|
|
expense: '鏀嚭'
|
|
}
|
|
return titles[type] || '浜ゆ槗'
|
|
}
|
|
|
|
// 鏍煎紡鍖栨椂闂?
|
|
const formatTime = (timeStr: string): string => {
|
|
const date = new Date(timeStr)
|
|
const month = (date.getMonth() + 1).toString().padStart(2, '0')
|
|
const day = date.getDate().toString().padStart(2, '0')
|
|
const hours = date.getHours().toString().padStart(2, '0')
|
|
const minutes = date.getMinutes().toString().padStart(2, '0')
|
|
return `${month}-${day} ${hours}:${minutes}`
|
|
}
|
|
|
|
// 鏄剧ず鏇村鎿嶄綔
|
|
const showMoreActions = () => {
|
|
uni.showActionSheet({
|
|
itemList: ['浜ゆ槗璁板綍', '瀹夊叏璁剧疆', '甯姪涓績'],
|
|
success: (res) => {
|
|
switch (res.tapIndex) {
|
|
case 0:
|
|
// 浜ゆ槗璁板綍宸茬粡鍦ㄥ綋鍓嶉〉
|
|
break
|
|
case 1:
|
|
uni.navigateTo({
|
|
url: '/pages/mall/consumer/settings'
|
|
})
|
|
break
|
|
case 2:
|
|
uni.navigateTo({
|
|
url: '/pages/info/help'
|
|
})
|
|
break
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
// 鍏呭€?
|
|
const recharge = () => {
|
|
showRechargePopup.value = true
|
|
rechargeAmount.value = ''
|
|
}
|
|
|
|
// 鎻愮幇
|
|
const withdraw = () => {
|
|
uni.navigateTo({
|
|
url: '/pages/mall/consumer/withdraw'
|
|
})
|
|
}
|
|
|
|
// 璺宠浆鍒颁紭鎯犲埜
|
|
const goToCoupons = () => {
|
|
uni.navigateTo({
|
|
url: '/pages/mall/consumer/coupons'
|
|
})
|
|
}
|
|
|
|
// 璺宠浆鍒扮孩鍖?
|
|
const goToRedPackets = () => {
|
|
uni.navigateTo({
|
|
url: '/pages/mall/consumer/red-packets'
|
|
})
|
|
}
|
|
|
|
// 璺宠浆鍒扮Н鍒?
|
|
const goToPoints = () => {
|
|
uni.navigateTo({
|
|
url: '/pages/mall/consumer/points'
|
|
})
|
|
}
|
|
|
|
// 璺宠浆鍒伴摱琛屽崱
|
|
const goToBankCards = () => {
|
|
uni.navigateTo({
|
|
url: '/pages/mall/consumer/bank-cards'
|
|
})
|
|
}
|
|
|
|
// 鍒囨崲杩囨护鍣?
|
|
const changeFilter = (filter: string) => {
|
|
activeFilter.value = filter
|
|
}
|
|
|
|
// 鍔犺浇鏇村
|
|
const loadMore = () => {
|
|
if (hasMore.value && !isLoading.value) {
|
|
loadTransactions(true)
|
|
}
|
|
}
|
|
|
|
// 閫夋嫨蹇嵎閲戦
|
|
const selectQuickAmount = (amount: number) => {
|
|
rechargeAmount.value = amount.toString()
|
|
}
|
|
|
|
// 纭鍏呭€?
|
|
const confirmRecharge = async () => {
|
|
if (!canRecharge.value) return
|
|
|
|
const amount = parseFloat(rechargeAmount.value)
|
|
if (isNaN(amount)) return
|
|
|
|
// 杩欓噷搴旇璺宠浆鍒版敮浠橀〉闈㈣繘琛屽厖鍊?
|
|
uni.navigateTo({
|
|
url: `/pages/mall/consumer/payment?type=recharge&amount=${amount}`
|
|
})
|
|
|
|
closeRechargePopup()
|
|
}
|
|
|
|
// 鍏抽棴鍏呭€煎脊绐?
|
|
const closeRechargePopup = () => {
|
|
showRechargePopup.value = false
|
|
rechargeAmount.value = ''
|
|
}
|
|
|
|
// 杩斿洖
|
|
const goBack = () => {
|
|
uni.navigateBack()
|
|
}
|
|
</script>
|
|
|
|
<style scoped>
|
|
/* 鍝嶅簲寮忓竷灞€浼樺寲 */
|
|
@media screen and (min-width: 768px) {
|
|
.wallet-content {
|
|
padding: 20px;
|
|
background-color: #f5f5f5;
|
|
}
|
|
|
|
.balance-overview {
|
|
border-radius: 12px;
|
|
margin-bottom: 20px;
|
|
max-width: 800px;
|
|
margin-left: auto;
|
|
margin-right: auto;
|
|
}
|
|
|
|
.assets-stats, .quick-actions, .transactions-section, .security-tips {
|
|
border-radius: 8px;
|
|
margin-bottom: 20px;
|
|
max-width: 800px;
|
|
margin-left: auto;
|
|
margin-right: auto;
|
|
}
|
|
|
|
.popup-content {
|
|
width: 400px;
|
|
left: 50%;
|
|
bottom: 50%;
|
|
transform: translate(-50%, 50%);
|
|
border-radius: 15px;
|
|
}
|
|
}
|
|
|
|
@media screen and (min-width: 1024px) {
|
|
.wallet-page {
|
|
flex-direction: row; /* 澶у睆涓嬫敼涓烘í鍚戝竷灞€ */
|
|
}
|
|
|
|
.wallet-header {
|
|
display: none; /* 澶у睆涓嬮殣钘忛《閮ㄦ爮 */
|
|
}
|
|
|
|
.wallet-content {
|
|
width: 100%;
|
|
max-width: 1000px;
|
|
margin: 0 auto;
|
|
}
|
|
}
|
|
|
|
.wallet-page {
|
|
display: flex;
|
|
flex-direction: column;
|
|
height: 100vh;
|
|
background-color: #f5f5f5;
|
|
}
|
|
|
|
.wallet-header {
|
|
background-color: #ffffff;
|
|
padding: 15px;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
border-bottom: 1px solid #e5e5e5;
|
|
}
|
|
|
|
.back-btn {
|
|
font-size: 24px;
|
|
color: #333333;
|
|
padding: 5px;
|
|
}
|
|
|
|
.wallet-content {
|
|
flex: 1;
|
|
}
|
|
|
|
.balance-overview {
|
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
padding: 30px 20px;
|
|
color: #ffffff;
|
|
}
|
|
|
|
.balance-label {
|
|
display: block;
|
|
font-size: 14px;
|
|
opacity: 0.9;
|
|
margin-bottom: 10px;
|
|
text-align: center;
|
|
}
|
|
|
|
.balance-value {
|
|
display: block;
|
|
font-size: 36px;
|
|
font-weight: bold;
|
|
margin-bottom: 20px;
|
|
text-align: center;
|
|
}
|
|
|
|
.balance-actions {
|
|
display: flex;
|
|
gap: 20px;
|
|
}
|
|
|
|
.action-btn {
|
|
flex: 1;
|
|
height: 40px;
|
|
border-radius: 20px;
|
|
font-size: 14px;
|
|
font-weight: bold;
|
|
border: none;
|
|
}
|
|
|
|
.action-btn.recharge {
|
|
background-color: #ffffff;
|
|
color: #667eea;
|
|
}
|
|
|
|
.action-btn.withdraw {
|
|
background-color: rgba(255, 255, 255, 0.2);
|
|
color: #ffffff;
|
|
border: 1px solid rgba(255, 255, 255, 0.5);
|
|
}
|
|
|
|
.assets-stats {
|
|
background-color: #ffffff;
|
|
padding: 20px;
|
|
display: flex;
|
|
justify-content: space-between;
|
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
|
}
|
|
|
|
.stat-item {
|
|
flex: 1;
|
|
text-align: center;
|
|
}
|
|
|
|
.stat-label {
|
|
display: block;
|
|
font-size: 12px;
|
|
color: #666666;
|
|
margin-bottom: 8px;
|
|
}
|
|
|
|
.stat-value {
|
|
display: block;
|
|
font-size: 16px;
|
|
font-weight: bold;
|
|
color: #333333;
|
|
}
|
|
|
|
.quick-actions {
|
|
background-color: #ffffff;
|
|
margin-top: 10px;
|
|
padding: 20px;
|
|
}
|
|
|
|
.action-grid {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
}
|
|
|
|
.action-item {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
}
|
|
|
|
.action-icon {
|
|
font-size: 28px;
|
|
margin-bottom: 8px;
|
|
}
|
|
|
|
.action-text {
|
|
font-size: 12px;
|
|
color: #666666;
|
|
}
|
|
|
|
.transactions-section {
|
|
background-color: #ffffff;
|
|
margin-top: 10px;
|
|
padding: 15px;
|
|
}
|
|
|
|
.section-header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
margin-bottom: 15px;
|
|
}
|
|
|
|
.section-title {
|
|
font-size: 16px;
|
|
font-weight: bold;
|
|
color: #333333;
|
|
}
|
|
|
|
.filter-tabs {
|
|
display: flex;
|
|
gap: 15px;
|
|
}
|
|
|
|
.filter-tab {
|
|
font-size: 14px;
|
|
color: #666666;
|
|
padding: 5px 0;
|
|
position: relative;
|
|
}
|
|
|
|
.filter-tab.active {
|
|
color: #007aff;
|
|
font-weight: bold;
|
|
}
|
|
|
|
.filter-tab.active::after {
|
|
content: '';
|
|
position: absolute;
|
|
bottom: 0;
|
|
left: 0;
|
|
right: 0;
|
|
height: 2px;
|
|
background-color: #007aff;
|
|
}
|
|
|
|
.empty-transactions {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
justify-content: center;
|
|
padding: 40px 20px;
|
|
}
|
|
|
|
.empty-icon {
|
|
font-size: 60px;
|
|
margin-bottom: 20px;
|
|
}
|
|
|
|
.empty-text {
|
|
font-size: 16px;
|
|
color: #666666;
|
|
margin-bottom: 10px;
|
|
}
|
|
|
|
.empty-subtext {
|
|
font-size: 14px;
|
|
color: #999999;
|
|
}
|
|
|
|
.transactions-list {
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
.transaction-item {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: flex-start;
|
|
padding: 15px 0;
|
|
border-bottom: 1px solid #f5f5f5;
|
|
}
|
|
|
|
.transaction-item:last-child {
|
|
border-bottom: none;
|
|
}
|
|
|
|
.transaction-left {
|
|
display: flex;
|
|
align-items: flex-start;
|
|
}
|
|
|
|
.transaction-icon {
|
|
font-size: 24px;
|
|
margin-right: 15px;
|
|
}
|
|
|
|
.transaction-info {
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
.transaction-title {
|
|
font-size: 14px;
|
|
color: #333333;
|
|
font-weight: bold;
|
|
margin-bottom: 5px;
|
|
}
|
|
|
|
.transaction-time {
|
|
font-size: 12px;
|
|
color: #999999;
|
|
margin-bottom: 3px;
|
|
}
|
|
|
|
.transaction-remark {
|
|
font-size: 12px;
|
|
color: #666666;
|
|
}
|
|
|
|
.transaction-right {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: flex-end;
|
|
}
|
|
|
|
.transaction-amount {
|
|
font-size: 16px;
|
|
font-weight: bold;
|
|
margin-bottom: 5px;
|
|
}
|
|
|
|
.transaction-amount.income {
|
|
color: #4caf50;
|
|
}
|
|
|
|
.transaction-amount.expense {
|
|
color: #333333;
|
|
}
|
|
|
|
.transaction-balance {
|
|
font-size: 12px;
|
|
color: #999999;
|
|
}
|
|
|
|
.loading-more,
|
|
.no-more {
|
|
padding: 20px;
|
|
text-align: center;
|
|
}
|
|
|
|
.loading-text,
|
|
.no-more-text {
|
|
color: #999999;
|
|
font-size: 14px;
|
|
}
|
|
|
|
.security-tips {
|
|
background-color: #ffffff;
|
|
margin-top: 10px;
|
|
padding: 20px;
|
|
}
|
|
|
|
.tip-title {
|
|
display: block;
|
|
font-size: 16px;
|
|
font-weight: bold;
|
|
color: #333333;
|
|
margin-bottom: 15px;
|
|
}
|
|
|
|
.tip-item {
|
|
display: block;
|
|
font-size: 12px;
|
|
color: #666666;
|
|
line-height: 1.6;
|
|
margin-bottom: 8px;
|
|
}
|
|
|
|
.tip-item:last-child {
|
|
margin-bottom: 0;
|
|
}
|
|
|
|
.recharge-popup {
|
|
position: fixed;
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
bottom: 0;
|
|
z-index: 999;
|
|
}
|
|
|
|
.popup-mask {
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
bottom: 0;
|
|
background-color: rgba(0, 0, 0, 0.5);
|
|
}
|
|
|
|
.popup-content {
|
|
position: absolute;
|
|
bottom: 0;
|
|
left: 0;
|
|
right: 0;
|
|
background-color: #ffffff;
|
|
border-top-left-radius: 15px;
|
|
border-top-right-radius: 15px;
|
|
padding: 20px;
|
|
}
|
|
|
|
.popup-header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
margin-bottom: 20px;
|
|
padding-bottom: 15px;
|
|
border-bottom: 1px solid #e5e5e5;
|
|
}
|
|
|
|
.popup-title {
|
|
font-size: 18px;
|
|
font-weight: bold;
|
|
color: #333333;
|
|
}
|
|
|
|
.popup-close {
|
|
font-size: 24px;
|
|
color: #999999;
|
|
padding: 5px;
|
|
}
|
|
|
|
.popup-body {
|
|
margin-bottom: 20px;
|
|
}
|
|
|
|
.amount-label {
|
|
display: block;
|
|
font-size: 14px;
|
|
color: #333333;
|
|
margin-bottom: 10px;
|
|
}
|
|
|
|
.amount-input {
|
|
display: flex;
|
|
align-items: center;
|
|
margin-bottom: 20px;
|
|
padding: 10px;
|
|
border: 1px solid #e5e5e5;
|
|
border-radius: 8px;
|
|
}
|
|
|
|
.currency-symbol {
|
|
font-size: 20px;
|
|
color: #333333;
|
|
margin-right: 10px;
|
|
}
|
|
|
|
.amount-field {
|
|
flex: 1;
|
|
font-size: 24px;
|
|
font-weight: bold;
|
|
color: #333333;
|
|
}
|
|
|
|
.quick-amounts {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 10px;
|
|
margin-bottom: 15px;
|
|
}
|
|
|
|
.quick-amount {
|
|
padding: 8px 15px;
|
|
border: 1px solid #e5e5e5;
|
|
border-radius: 15px;
|
|
font-size: 14px;
|
|
color: #333333;
|
|
}
|
|
|
|
.quick-amount.active {
|
|
background-color: #007aff;
|
|
color: #ffffff;
|
|
border-color: #007aff;
|
|
}
|
|
|
|
.recharge-tip {
|
|
display: block;
|
|
font-size: 12px;
|
|
color: #999999;
|
|
}
|
|
|
|
.popup-footer {
|
|
display: flex;
|
|
gap: 15px;
|
|
}
|
|
|
|
.cancel-btn,
|
|
.confirm-btn {
|
|
flex: 1;
|
|
height: 45px;
|
|
border-radius: 22.5px;
|
|
font-size: 16px;
|
|
font-weight: bold;
|
|
border: none;
|
|
}
|
|
|
|
.cancel-btn {
|
|
background-color: #f5f5f5;
|
|
color: #666666;
|
|
}
|
|
|
|
.confirm-btn {
|
|
background-color: #007aff;
|
|
color: #ffffff;
|
|
}
|
|
|
|
.confirm-btn.disabled {
|
|
background-color: #cccccc;
|
|
opacity: 0.6;
|
|
}
|
|
</style>
|
|
|