243 lines
6.0 KiB
Plaintext
243 lines
6.0 KiB
Plaintext
<template>
|
|
<view class="bank-cards-page">
|
|
<view class="card-list">
|
|
<view v-for="card in cards" :key="card.id" class="card-item" :class="getCardClass(card.bank_name)">
|
|
<view class="card-bg-mask"></view>
|
|
<view class="card-content">
|
|
<view class="card-header">
|
|
<text class="bank-name">{{ card.bank_name }}</text>
|
|
<text class="card-type">{{ card.card_type === 'credit' ? '信用卡' : '储蓄卡' }}</text>
|
|
</view>
|
|
<view class="card-number">
|
|
<text class="dots">**** **** ****</text>
|
|
<text class="last-digits">{{ card.card_no_last4 }}</text>
|
|
</view>
|
|
<view class="delete-btn" @click.stop="deleteCard(card)">
|
|
<text class="del-text">✕</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<view class="add-card-btn" @click="addCard">
|
|
<text class="plus-icon">+</text>
|
|
<text>添加银行卡</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</template>
|
|
|
|
<script setup lang="uts">
|
|
import { ref, onMounted } from 'vue'
|
|
import { supabaseService } from '@/utils/supabaseService.uts'
|
|
|
|
type BankCard = {
|
|
id: string
|
|
user_id: string
|
|
bank_name: string
|
|
card_no_last4: string
|
|
card_type: string
|
|
holder_name: string
|
|
is_default: boolean
|
|
}
|
|
|
|
const cards = ref<BankCard[]>([])
|
|
const loading = ref(true)
|
|
|
|
const loadData = async () => {
|
|
loading.value = true
|
|
try {
|
|
const rawList = await supabaseService.getUserBankCards()
|
|
const cardList: BankCard[] = []
|
|
|
|
// Use for loop instead of map to avoid complex closure typing issues
|
|
for (let i = 0; i < rawList.length; i++) {
|
|
const item = rawList[i]
|
|
let id = ''
|
|
let bankName = ''
|
|
let last4 = ''
|
|
let type = 'debit'
|
|
let holder = ''
|
|
let isDef = false
|
|
|
|
if (item instanceof UTSJSONObject) {
|
|
id = item.getString('id') ?? ''
|
|
bankName = item.getString('bank_name') ?? ''
|
|
last4 = item.getString('card_no_last4') ?? ''
|
|
type = item.getString('card_type') ?? 'debit'
|
|
holder = item.getString('holder_name') ?? ''
|
|
isDef = item.getBoolean('is_default') ?? false
|
|
} else {
|
|
const obj = JSON.parse(JSON.stringify(item)) as UTSJSONObject
|
|
id = obj.getString('id') ?? ''
|
|
bankName = obj.getString('bank_name') ?? ''
|
|
last4 = obj.getString('card_no_last4') ?? ''
|
|
type = obj.getString('card_type') ?? 'debit'
|
|
holder = obj.getString('holder_name') ?? ''
|
|
isDef = obj.getBoolean('is_default') ?? false
|
|
}
|
|
|
|
cardList.push({
|
|
id: id,
|
|
user_id: '',
|
|
bank_name: bankName,
|
|
card_no_last4: last4,
|
|
card_type: type,
|
|
holder_name: holder,
|
|
is_default: isDef
|
|
} as BankCard)
|
|
}
|
|
|
|
cards.value = cardList
|
|
} catch (e) {
|
|
console.error(e)
|
|
} finally {
|
|
loading.value = false
|
|
}
|
|
}
|
|
|
|
onShow(() => {
|
|
loadData()
|
|
})
|
|
|
|
const addCard = () => {
|
|
uni.navigateTo({
|
|
url: '/pages/mall/consumer/bank-cards/add'
|
|
})
|
|
}
|
|
|
|
const doDeleteCard = async (card: BankCard): Promise<void> => {
|
|
const success = await supabaseService.deleteBankCard(card.id)
|
|
if (success) {
|
|
uni.showToast({ title: '已删除' })
|
|
loadData()
|
|
} else {
|
|
uni.showToast({ title: '删除失败', icon: 'none' })
|
|
}
|
|
}
|
|
|
|
const deleteCard = (card: BankCard) => {
|
|
uni.showModal({
|
|
title: '删除银行卡',
|
|
content: `确认删除尾号${card.card_no_last4}的${card.bank_name}卡片吗?`,
|
|
success: (res) => {
|
|
if (res.confirm) {
|
|
doDeleteCard(card)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
const getCardClass = (bankName: string): string => {
|
|
if (bankName.includes('招商')) return 'cmb'
|
|
if (bankName.includes('建设')) return 'ccb'
|
|
if (bankName.includes('工商')) return 'icbc'
|
|
if (bankName.includes('农业')) return 'abc'
|
|
return 'default-bank'
|
|
}
|
|
|
|
</script>
|
|
|
|
<style>
|
|
.bank-cards-page {
|
|
padding: 15px;
|
|
background-color: #f5f5f5;
|
|
flex: 1;
|
|
height: 140px;
|
|
border-radius: 12px;
|
|
margin-bottom: 15px;
|
|
color: #fff;
|
|
position: relative;
|
|
overflow: hidden;
|
|
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
|
|
}
|
|
|
|
.cmb { background: linear-gradient(135deg, #f55, #c00); }
|
|
.ccb { background: linear-gradient(135deg, #09f, #00609c); }
|
|
.icbc { background: linear-gradient(135deg, #f66, #c00); }
|
|
.abc { background: linear-gradient(135deg, #0b9, #086); }
|
|
.default-bank { background: linear-gradient(135deg, #666, #333); }
|
|
|
|
.card-content {
|
|
padding: 20px;
|
|
z-index: 2;
|
|
position: relative;
|
|
height: 100%;
|
|
box-sizing: border-box;
|
|
display: flex;
|
|
flex-direction: column;
|
|
justify-content: space-between;
|
|
}
|
|
|
|
.card-header {
|
|
display: flex;
|
|
align-items: center;
|
|
}
|
|
|
|
.bank-name {
|
|
font-size: 18px;
|
|
font-weight: bold;
|
|
margin-right: 10px;
|
|
}
|
|
|
|
.card-type {
|
|
font-size: 12px;
|
|
background-color: rgba(255,255,255,0.2);
|
|
padding: 2px 6px;
|
|
border-radius: 4px;
|
|
}
|
|
|
|
.card-number {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: flex-end; /* 右对齐 */
|
|
margin-bottom: 10px;
|
|
}
|
|
|
|
.dots {
|
|
font-size: 24px;
|
|
margin-right: 15px;
|
|
line-height: 1;
|
|
}
|
|
|
|
.last-digits {
|
|
font-size: 24px;
|
|
font-family: monospace;
|
|
}
|
|
|
|
.add-card-btn {
|
|
background-color: #fff;
|
|
height: 60px;
|
|
border-radius: 8px;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
color: #666;
|
|
font-size: 16px;
|
|
border: 1px dashed #ccc;
|
|
}
|
|
|
|
.plus-icon {
|
|
font-size: 24px;
|
|
margin-right: 5px;
|
|
/* font-weight: 300; removed */
|
|
}
|
|
|
|
.delete-btn {
|
|
position: absolute;
|
|
top: 15px;
|
|
right: 15px;
|
|
width: 24px;
|
|
height: 24px;
|
|
background-color: rgba(0,0,0,0.2);
|
|
border-radius: 12px;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
|
|
.del-text {
|
|
color: #fff;
|
|
font-size: 14px;
|
|
font-weight: bold;
|
|
}
|
|
</style> |