425 lines
10 KiB
Vue
425 lines
10 KiB
Vue
<template>
|
||
<clinic-page-layout title="提现管理" :show-back="true">
|
||
<view class="withdrawal-container">
|
||
|
||
<!-- 高级虚拟银行卡片 -->
|
||
<view class="premium-bank-card">
|
||
<view class="card-top">
|
||
<text class="bank-name">{{ cardTitle || '银行卡' }}</text>
|
||
<text class="card-type">储蓄卡</text>
|
||
</view>
|
||
<!-- 使用完整的 maskCard 方法处理卡号显示 -->
|
||
<view class="card-number">
|
||
<text class="card-val">{{ maskCard(card.bank_card) || '**** **** **** ----' }}</text>
|
||
</view>
|
||
<view class="card-bottom">
|
||
<text class="bank-sub">开户行:{{ card.bank_name || '-' }}</text>
|
||
</view>
|
||
<!-- 装饰几何图案 -->
|
||
<view class="card-decorator"></view>
|
||
</view>
|
||
|
||
<!-- 核心统计网格 -->
|
||
<view class="stats-grid">
|
||
<view v-for="b in balanceItems" :key="b.key" class="stat-island">
|
||
<text class="stat-label">{{ b.label }}</text>
|
||
<text class="stat-val">{{ b.display }}</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 金刚区操作栏 -->
|
||
<view class="action-bar">
|
||
<view v-for="m in actions" :key="m.key" class="action-item" hover-class="action-hover" @click="onAction(m.key)">
|
||
<text class="action-text">{{ m.label }}</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 提现记录列表 -->
|
||
<view class="list-section">
|
||
<view class="section-hd">
|
||
<text class="section-title">提现记录</text>
|
||
</view>
|
||
|
||
<view class="record-list">
|
||
<view
|
||
v-for="item in withdrawalList"
|
||
:key="item._wxKey"
|
||
class="record-item"
|
||
hover-class="item-hover"
|
||
@click="goWithdrawalDetail(item)"
|
||
>
|
||
<view class="record-main">
|
||
<text class="record-title">提现到银行卡</text>
|
||
<!-- 三元表达式处理颜色,完美兼容微信小程序 -->
|
||
<text class="record-amount" :class="item.status === 1 ? 'amount-success' : ''">-{{ item.amount || '0.00' }}</text>
|
||
</view>
|
||
<view class="record-sub">
|
||
<text class="record-time">{{ item.time || '-' }}</text>
|
||
<text
|
||
class="record-status"
|
||
:class="item.status === 1 ? 'text-success' : (item.status === 2 || item.status === 3 ? 'text-danger' : 'text-warning')"
|
||
>
|
||
{{ item.statusText || '处理中' }}
|
||
</text>
|
||
</view>
|
||
</view>
|
||
<view v-if="withdrawalList.length === 0" class="empty-state">
|
||
暂无提现记录
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
</view>
|
||
</clinic-page-layout>
|
||
</template>
|
||
|
||
<script>
|
||
import ClinicPageLayout from '@/subPackages/sub_clinic_admin/components/clinic-page-layout.vue'
|
||
import { getClinicAdminCard, getClinicAdminBalance, getWithdrawalList } from '@/api/clinicAdmin.js'
|
||
import { withWxKey } from '@/utils/wxListKey.js'
|
||
import { formatMoney } from '@/subPackages/sub_clinic_admin/common/format.js'
|
||
import { withdrawalCheckStatusText, formatDateTime } from '@/subPackages/sub_clinic_admin/common/display.js'
|
||
|
||
export default {
|
||
components: { ClinicPageLayout },
|
||
data() {
|
||
return {
|
||
cardTitle: '我的账户',
|
||
card: {
|
||
bank_card: '',
|
||
bank_name: ''
|
||
},
|
||
balanceItems: [
|
||
{ key: 'balance', label: '可提现余额 (元)', display: '0.00' },
|
||
{ key: 'reviewing', label: '审核中金额 (元)', display: '0.00' },
|
||
{ key: 'pending', label: '待结算收益 (元)', display: '0.00' },
|
||
],
|
||
actions: [
|
||
{ key: 'apply', label: '申请提现' },
|
||
{ key: 'settlement', label: '结算记录' },
|
||
{ key: 'accountChange', label: '资金变动' },
|
||
],
|
||
withdrawalList: [],
|
||
page: 1,
|
||
loading: false
|
||
}
|
||
},
|
||
onShow() {
|
||
this.loadCard();
|
||
this.loadBalance();
|
||
this.reloadList();
|
||
},
|
||
onReachBottom() {
|
||
if (!this.loading) {
|
||
this.loadList(this.page + 1, true);
|
||
}
|
||
},
|
||
methods: {
|
||
// 银行卡号掩码处理,保留后四位
|
||
maskCard(cardStr) {
|
||
if(!cardStr) return '**** **** **** ----';
|
||
const last4 = cardStr.slice(-4);
|
||
return `**** **** **** ${last4}`;
|
||
},
|
||
|
||
// 快捷操作跳转
|
||
onAction(key) {
|
||
if (key === 'apply') {
|
||
uni.navigateTo({ url: '/subPackages/sub_clinic_admin/withdrawal/apply' });
|
||
} else if (key === 'edit') {
|
||
uni.navigateTo({ url: '/subPackages/sub_clinic_admin/withdrawal/card-edit' });
|
||
} else if (key === 'settlement') {
|
||
uni.navigateTo({ url: '/subPackages/sub_clinic_admin/withdrawal/settlement/index' });
|
||
} else if (key === 'accountChange') {
|
||
uni.navigateTo({ url: '/subPackages/sub_clinic_admin/withdrawal/account-change/index' });
|
||
}
|
||
},
|
||
|
||
// 提现详情跳转
|
||
goWithdrawalDetail(item) {
|
||
uni.navigateTo({ url: `/subPackages/sub_clinic_admin/withdrawal/record-detail?id=${item.id}` });
|
||
},
|
||
|
||
// 获取绑定的银行卡信息
|
||
loadCard() {
|
||
getClinicAdminCard().then(w => {
|
||
if (w.ok && w.data) {
|
||
this.card = w.data;
|
||
this.cardTitle = w.data.bank_user_name || '我的账户';
|
||
}
|
||
});
|
||
},
|
||
|
||
// 获取余额数据
|
||
loadBalance() {
|
||
getClinicAdminBalance().then(w => {
|
||
if (w.ok && w.data) {
|
||
const fmt = (v) => formatMoney(v || 0).replace('¥', '')
|
||
const map = {
|
||
balance: fmt(w.data.balance),
|
||
reviewing: fmt(w.data.withdrawn_frozen),
|
||
pending: fmt(w.data.pending_earnings),
|
||
}
|
||
this.balanceItems = this.balanceItems.map(item => ({
|
||
...item,
|
||
display: map[item.key] ?? '0.00',
|
||
}))
|
||
}
|
||
});
|
||
},
|
||
|
||
// 刷新提现列表
|
||
reloadList() {
|
||
this.page = 1;
|
||
this.loadList(1, false);
|
||
},
|
||
|
||
// 加载提现列表数据
|
||
loadList(page, append) {
|
||
this.loading = true;
|
||
getWithdrawalList({ page, pageSize: 15 }).then(w => {
|
||
if (w.ok && w.data) {
|
||
const items = (w.data.items || []).map(item => ({
|
||
...item,
|
||
amount: formatMoney(item.apply_cash).replace('¥', ''),
|
||
time: formatDateTime(item.apply_time),
|
||
status: item.check_status,
|
||
statusText: withdrawalCheckStatusText(item.check_status)
|
||
}));
|
||
|
||
const listWithKey = withWxKey(items, 'id', 'wd');
|
||
this.withdrawalList = append ? this.withdrawalList.concat(listWithKey) : listWithKey;
|
||
this.page = page;
|
||
}
|
||
}).finally(() => {
|
||
this.loading = false;
|
||
});
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
$theme-primary: #6acdbb;
|
||
$color-bg-base: #F5F7F8;
|
||
$color-text-main: #1D2129;
|
||
$color-text-body: #4E5969;
|
||
$color-text-muted: #86909C;
|
||
|
||
.withdrawal-container {
|
||
background-color: $color-bg-base;
|
||
min-height: 100vh;
|
||
padding: 24rpx 24rpx 60rpx;
|
||
}
|
||
|
||
/* 高级虚拟银行卡 */
|
||
.premium-bank-card {
|
||
position: relative;
|
||
background: linear-gradient(135deg, #2C303A 0%, #1A1D24 100%);
|
||
border-radius: 32rpx;
|
||
padding: 40rpx;
|
||
color: #fff;
|
||
box-shadow: 0 16rpx 32rpx rgba(26, 29, 36, 0.15);
|
||
margin-bottom: 24rpx;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.card-top {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-bottom: 40rpx;
|
||
position: relative;
|
||
z-index: 2;
|
||
}
|
||
|
||
.bank-name {
|
||
font-size: 32rpx;
|
||
font-weight: 600;
|
||
letter-spacing: 2rpx;
|
||
}
|
||
|
||
.card-type {
|
||
font-size: 24rpx;
|
||
color: rgba(255,255,255,0.6);
|
||
}
|
||
|
||
.card-number {
|
||
font-family: monospace, sans-serif;
|
||
font-size: 44rpx;
|
||
font-weight: 600;
|
||
margin-bottom: 40rpx;
|
||
position: relative;
|
||
z-index: 2;
|
||
letter-spacing: 2rpx;
|
||
}
|
||
|
||
.card-bottom {
|
||
font-size: 24rpx;
|
||
color: rgba(255,255,255,0.6);
|
||
position: relative;
|
||
z-index: 2;
|
||
}
|
||
|
||
.card-decorator {
|
||
position: absolute;
|
||
right: -40rpx;
|
||
bottom: -60rpx;
|
||
width: 240rpx;
|
||
height: 240rpx;
|
||
border: 40rpx solid rgba(255,255,255,0.03);
|
||
border-radius: 50%;
|
||
z-index: 1;
|
||
}
|
||
|
||
/* 统计网格 */
|
||
.stats-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(3, 1fr);
|
||
gap: 20rpx;
|
||
margin-bottom: 24rpx;
|
||
}
|
||
|
||
.stat-island {
|
||
background: #fff;
|
||
border-radius: 24rpx;
|
||
padding: 32rpx 24rpx;
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: center;
|
||
}
|
||
|
||
.stat-label {
|
||
font-size: 24rpx;
|
||
color: $color-text-muted;
|
||
margin-bottom: 12rpx;
|
||
}
|
||
|
||
.stat-val {
|
||
font-size: 36rpx;
|
||
font-weight: 700;
|
||
color: $color-text-main;
|
||
font-family: DIN Alternate, monospace, sans-serif;
|
||
}
|
||
|
||
/* 金刚区操作栏 */
|
||
.action-bar {
|
||
display: flex;
|
||
background: #fff;
|
||
border-radius: 24rpx;
|
||
margin-bottom: 32rpx;
|
||
padding: 12rpx 0;
|
||
}
|
||
|
||
.action-item {
|
||
flex: 1;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
padding: 24rpx 0;
|
||
position: relative;
|
||
transition: background-color 0.2s;
|
||
|
||
&:not(:last-child)::after {
|
||
content: '';
|
||
position: absolute;
|
||
right: 0;
|
||
top: 30%;
|
||
height: 40%;
|
||
width: 2rpx;
|
||
background-color: #F2F3F5;
|
||
}
|
||
}
|
||
|
||
.action-hover {
|
||
background-color: #FAFAFA;
|
||
}
|
||
|
||
.action-text {
|
||
font-size: 26rpx;
|
||
font-weight: 500;
|
||
color: $color-text-main;
|
||
}
|
||
|
||
/* 提现记录列表 */
|
||
.list-section {
|
||
background: #fff;
|
||
border-radius: 24rpx;
|
||
padding: 32rpx 24rpx;
|
||
}
|
||
|
||
.section-hd {
|
||
margin-bottom: 24rpx;
|
||
padding-left: 8rpx;
|
||
}
|
||
|
||
.section-title {
|
||
font-size: 30rpx;
|
||
font-weight: 700;
|
||
color: $color-text-main;
|
||
}
|
||
|
||
.record-item {
|
||
padding: 24rpx 8rpx;
|
||
border-bottom: 1rpx solid #F2F3F5;
|
||
transition: background-color 0.2s;
|
||
|
||
&:last-child {
|
||
border-bottom: none;
|
||
}
|
||
}
|
||
|
||
.item-hover {
|
||
background-color: #F7F8FA;
|
||
border-radius: 12rpx;
|
||
}
|
||
|
||
.record-main {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-bottom: 12rpx;
|
||
}
|
||
|
||
.record-title {
|
||
font-size: 28rpx;
|
||
color: $color-text-main;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.record-amount {
|
||
font-size: 32rpx;
|
||
font-weight: 700;
|
||
color: $color-text-main;
|
||
font-family: DIN Alternate, monospace, sans-serif;
|
||
|
||
&.amount-success {
|
||
color: $theme-primary; /* 成功的金额变绿 */
|
||
}
|
||
}
|
||
|
||
.record-sub {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
font-size: 24rpx;
|
||
}
|
||
|
||
.record-time {
|
||
color: $color-text-muted;
|
||
}
|
||
|
||
.record-status {
|
||
font-weight: 500;
|
||
}
|
||
.text-success { color: $theme-primary; }
|
||
.text-danger { color: #F53F3F; }
|
||
.text-warning { color: #F5A623; }
|
||
|
||
.empty-state {
|
||
text-align: center;
|
||
color: $color-text-muted;
|
||
padding: 60rpx 0;
|
||
font-size: 26rpx;
|
||
}
|
||
</style> |