手机端增加提现功能
This commit is contained in:
@@ -136,10 +136,7 @@ async function openPostRentalNotice() {
|
||||
}
|
||||
|
||||
function handleWithdraw() {
|
||||
showDialog({
|
||||
title: '提现提示',
|
||||
message: '为了您的资金安全,提现请前往电脑端网页版进行操作。',
|
||||
})
|
||||
router.push('/m/wallet/withdrawal')
|
||||
}
|
||||
|
||||
function goOrders(tabKey: string) {
|
||||
@@ -364,7 +361,7 @@ function resolveAvatarURL(url: string | undefined | null) {
|
||||
<div class="icon-wrap purple"><van-icon name="shop-o" :size="22" /></div>
|
||||
<span>我的商品</span>
|
||||
</div>
|
||||
<div class="grid-item" @click="openLedgers">
|
||||
<div class="grid-item" @click="router.push('/m/wallet/withdrawal')">
|
||||
<div class="icon-wrap teal"><van-icon name="balance-o" :size="22" /></div>
|
||||
<span>提现/账单</span>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,886 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, onMounted, reactive, ref } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { showDialog, showToast } from 'vant'
|
||||
|
||||
import {
|
||||
cancelWithdrawal,
|
||||
createPaymentAccount,
|
||||
createWithdrawal,
|
||||
fetchPaymentAccounts,
|
||||
fetchWithdrawals,
|
||||
type AccountType,
|
||||
type PaymentAccount,
|
||||
type WithdrawalRequest,
|
||||
} from '@/features/wallet/api/withdrawal'
|
||||
import { fetchWalletBalance, type WalletAccount } from '@/features/wallet/api/wallet'
|
||||
import { uploadFile } from '@/shared/api/files'
|
||||
import { readError } from '@/shared/utils/error'
|
||||
import { formatCent, formatMoney, yuanToCent } from '@/shared/utils/money'
|
||||
import { formatDateMinute } from '@/shared/utils/time'
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
const loading = ref(false)
|
||||
const submitting = ref(false)
|
||||
const addingAccount = ref(false)
|
||||
const uploadingCertificate = ref(false)
|
||||
const showAccountPopup = ref(false)
|
||||
const account = ref<WalletAccount | null>(null)
|
||||
const paymentAccounts = ref<PaymentAccount[]>([])
|
||||
const withdrawals = ref<WithdrawalRequest[]>([])
|
||||
|
||||
const MIN_AMOUNT = 10
|
||||
const MAX_AMOUNT = 5000
|
||||
|
||||
const withdrawForm = reactive({
|
||||
payment_account_id: 0,
|
||||
amount: '' as number | '',
|
||||
})
|
||||
|
||||
const accountForm = reactive({
|
||||
account_type: 'alipay' as AccountType,
|
||||
account_name: '',
|
||||
account_no: '',
|
||||
bank_name: '',
|
||||
bank_branch: '',
|
||||
certificate_urls: [] as string[],
|
||||
})
|
||||
|
||||
const selectedAccount = computed(() =>
|
||||
paymentAccounts.value.find(item => item.id === withdrawForm.payment_account_id)
|
||||
)
|
||||
|
||||
const amountValue = computed(() => Number(withdrawForm.amount || 0))
|
||||
const amountCent = computed(() => yuanToCent(amountValue.value))
|
||||
const availableBalanceCent = computed(() => account.value?.available_balance_cent || 0)
|
||||
const canWithdraw = computed(
|
||||
() =>
|
||||
withdrawForm.payment_account_id > 0 &&
|
||||
amountValue.value >= MIN_AMOUNT &&
|
||||
amountValue.value <= MAX_AMOUNT &&
|
||||
amountCent.value <= availableBalanceCent.value &&
|
||||
!submitting.value
|
||||
)
|
||||
|
||||
onMounted(loadData)
|
||||
|
||||
async function loadData() {
|
||||
loading.value = true
|
||||
try {
|
||||
const [balanceData, accountsData, withdrawalsData] = await Promise.all([
|
||||
fetchWalletBalance(),
|
||||
fetchPaymentAccounts(1, 100),
|
||||
fetchWithdrawals(1, 20),
|
||||
])
|
||||
account.value = balanceData
|
||||
paymentAccounts.value = accountsData.items
|
||||
withdrawals.value = withdrawalsData.items
|
||||
const currentStillExists = paymentAccounts.value.some(
|
||||
item => item.id === withdrawForm.payment_account_id
|
||||
)
|
||||
if (!currentStillExists) {
|
||||
const defaultAccount = paymentAccounts.value.find(item => item.is_default)
|
||||
withdrawForm.payment_account_id = defaultAccount?.id || paymentAccounts.value[0]?.id || 0
|
||||
}
|
||||
} catch (error) {
|
||||
showToast({ message: readError(error, '加载失败'), icon: 'cross' })
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function handleSubmit() {
|
||||
if (!canWithdraw.value || !selectedAccount.value) return
|
||||
try {
|
||||
await showDialog({
|
||||
title: '确认提现',
|
||||
message: `提现 ¥${formatMoney(amountValue.value)} 到 ${selectedAccount.value.account_name}(${selectedAccount.value.account_no})?`,
|
||||
confirmButtonText: '确认提交',
|
||||
cancelButtonText: '再看看',
|
||||
showCancelButton: true,
|
||||
})
|
||||
} catch {
|
||||
return
|
||||
}
|
||||
|
||||
submitting.value = true
|
||||
try {
|
||||
await createWithdrawal({
|
||||
payment_account_id: withdrawForm.payment_account_id,
|
||||
amount_cent: amountCent.value,
|
||||
})
|
||||
showToast({ message: '提现申请已提交', icon: 'passed' })
|
||||
withdrawForm.amount = ''
|
||||
await loadData()
|
||||
} catch (error) {
|
||||
showToast({ message: readError(error, '提现申请失败'), icon: 'cross' })
|
||||
} finally {
|
||||
submitting.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function handleCancel(item: WithdrawalRequest) {
|
||||
try {
|
||||
await showDialog({
|
||||
title: '取消提现',
|
||||
message: '确定要取消此提现申请吗?',
|
||||
confirmButtonText: '确认取消',
|
||||
cancelButtonText: '返回',
|
||||
showCancelButton: true,
|
||||
})
|
||||
} catch {
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
await cancelWithdrawal(item.id)
|
||||
showToast({ message: '已取消提现', icon: 'passed' })
|
||||
await loadData()
|
||||
} catch (error) {
|
||||
showToast({ message: readError(error, '取消失败'), icon: 'cross' })
|
||||
}
|
||||
}
|
||||
|
||||
function openAccountPopup() {
|
||||
Object.assign(accountForm, {
|
||||
account_type: 'alipay' as AccountType,
|
||||
account_name: '',
|
||||
account_no: '',
|
||||
bank_name: '',
|
||||
bank_branch: '',
|
||||
certificate_urls: [] as string[],
|
||||
})
|
||||
showAccountPopup.value = true
|
||||
}
|
||||
|
||||
async function handleAddAccount() {
|
||||
if (!accountForm.account_name.trim()) {
|
||||
showToast({ message: '请输入账户名', icon: 'warning-o' })
|
||||
return
|
||||
}
|
||||
if (!accountForm.account_no.trim()) {
|
||||
showToast({ message: accountForm.account_type === 'bank' ? '请输入银行卡号' : '请输入账号', icon: 'warning-o' })
|
||||
return
|
||||
}
|
||||
if (accountForm.account_type === 'bank' && !accountForm.bank_name.trim()) {
|
||||
showToast({ message: '请输入银行名称', icon: 'warning-o' })
|
||||
return
|
||||
}
|
||||
|
||||
addingAccount.value = true
|
||||
try {
|
||||
const created = await createPaymentAccount({
|
||||
account_type: accountForm.account_type,
|
||||
account_name: accountForm.account_name.trim(),
|
||||
account_no: accountForm.account_no.trim(),
|
||||
bank_name: accountForm.account_type === 'bank' ? accountForm.bank_name.trim() : '',
|
||||
bank_branch: accountForm.account_type === 'bank' ? accountForm.bank_branch.trim() : '',
|
||||
certificate_urls: accountForm.certificate_urls,
|
||||
})
|
||||
showToast({ message: '收款账号已添加', icon: 'passed' })
|
||||
showAccountPopup.value = false
|
||||
await loadData()
|
||||
withdrawForm.payment_account_id = created.id
|
||||
} catch (error) {
|
||||
showToast({ message: readError(error, '添加失败'), icon: 'cross' })
|
||||
} finally {
|
||||
addingAccount.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function handleCertificateUpload(event: Event) {
|
||||
const input = event.target as HTMLInputElement
|
||||
const file = input.files?.[0]
|
||||
input.value = ''
|
||||
if (!file) return
|
||||
if (!file.type.startsWith('image/')) {
|
||||
showToast({ message: '只能上传图片文件', icon: 'warning-o' })
|
||||
return
|
||||
}
|
||||
if (file.size > 5 * 1024 * 1024) {
|
||||
showToast({ message: '图片大小不能超过5MB', icon: 'warning-o' })
|
||||
return
|
||||
}
|
||||
if (accountForm.certificate_urls.length >= 3) {
|
||||
showToast({ message: '最多上传3张图片', icon: 'warning-o' })
|
||||
return
|
||||
}
|
||||
|
||||
uploadingCertificate.value = true
|
||||
try {
|
||||
const uploaded = await uploadFile(file, 'payment-cert')
|
||||
const publicURL = uploaded.url.replace('/api/files/object', '/api/public/files/object')
|
||||
accountForm.certificate_urls.push(publicURL)
|
||||
showToast({ message: '图片已上传', icon: 'passed' })
|
||||
} catch (error) {
|
||||
showToast({ message: readError(error, '上传失败'), icon: 'cross' })
|
||||
} finally {
|
||||
uploadingCertificate.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function removeCertificate(index: number) {
|
||||
accountForm.certificate_urls.splice(index, 1)
|
||||
}
|
||||
|
||||
function selectAccount(id: number) {
|
||||
withdrawForm.payment_account_id = id
|
||||
}
|
||||
|
||||
function accountTypeLabel(type: string) {
|
||||
const labels: Record<string, string> = {
|
||||
alipay: '支付宝',
|
||||
wechat: '微信',
|
||||
bank: '银行卡',
|
||||
}
|
||||
return labels[type] || type
|
||||
}
|
||||
|
||||
function accountTypeIcon(type: string) {
|
||||
const icons: Record<string, string> = {
|
||||
alipay: 'gold-coin-o',
|
||||
wechat: 'chat-o',
|
||||
bank: 'credit-pay',
|
||||
}
|
||||
return icons[type] || 'balance-o'
|
||||
}
|
||||
|
||||
function statusLabel(status: string) {
|
||||
const labels: Record<string, string> = {
|
||||
pending: '待审核',
|
||||
processing: '处理中',
|
||||
completed: '已完成',
|
||||
rejected: '已拒绝',
|
||||
cancelled: '已取消',
|
||||
}
|
||||
return labels[status] || status
|
||||
}
|
||||
|
||||
function statusType(status: string): 'primary' | 'success' | 'danger' | 'warning' | undefined {
|
||||
const types: Record<string, 'primary' | 'success' | 'danger' | 'warning'> = {
|
||||
pending: 'warning',
|
||||
processing: 'primary',
|
||||
completed: 'success',
|
||||
rejected: 'danger',
|
||||
}
|
||||
return types[status]
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<main class="mobile-withdrawal">
|
||||
<header class="page-header">
|
||||
<button class="back-btn" type="button" @click="router.back()">
|
||||
<van-icon name="arrow-left" :size="20" />
|
||||
</button>
|
||||
<h1>提现</h1>
|
||||
<button class="refresh-btn" type="button" @click="loadData">
|
||||
<van-icon name="replay" :size="18" />
|
||||
</button>
|
||||
</header>
|
||||
|
||||
<section class="balance-panel">
|
||||
<span>可用余额</span>
|
||||
<strong>¥{{ formatCent(availableBalanceCent) }}</strong>
|
||||
<small>冻结余额 ¥{{ formatCent(account?.frozen_balance_cent) }}</small>
|
||||
</section>
|
||||
|
||||
<section class="withdraw-card">
|
||||
<div class="section-title">
|
||||
<h2>申请提现</h2>
|
||||
<button type="button" @click="openAccountPopup">
|
||||
<van-icon name="plus" :size="14" />
|
||||
添加账号
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<van-loading v-if="loading && !paymentAccounts.length" class="center-loading" />
|
||||
|
||||
<div v-else-if="!paymentAccounts.length" class="empty-state">
|
||||
<van-icon name="card" :size="32" />
|
||||
<p>还没有收款账号</p>
|
||||
<van-button type="primary" round size="small" @click="openAccountPopup">
|
||||
添加收款账号
|
||||
</van-button>
|
||||
</div>
|
||||
|
||||
<template v-else>
|
||||
<div class="account-list">
|
||||
<button
|
||||
v-for="item in paymentAccounts"
|
||||
:key="item.id"
|
||||
type="button"
|
||||
class="account-option"
|
||||
:class="{ active: item.id === withdrawForm.payment_account_id }"
|
||||
@click="selectAccount(item.id)"
|
||||
>
|
||||
<span class="account-icon">
|
||||
<van-icon :name="accountTypeIcon(item.account_type)" :size="18" />
|
||||
</span>
|
||||
<span class="account-main">
|
||||
<strong>{{ accountTypeLabel(item.account_type) }} · {{ item.account_name }}</strong>
|
||||
<small>{{ item.account_no }}</small>
|
||||
</span>
|
||||
<van-tag v-if="item.is_default" type="warning" plain>默认</van-tag>
|
||||
<van-icon
|
||||
:name="item.id === withdrawForm.payment_account_id ? 'checked' : 'circle'"
|
||||
:size="18"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<van-field
|
||||
v-model.number="withdrawForm.amount"
|
||||
type="number"
|
||||
label="提现金额"
|
||||
placeholder="请输入提现金额"
|
||||
input-align="right"
|
||||
>
|
||||
<template #left-icon>¥</template>
|
||||
</van-field>
|
||||
|
||||
<div class="amount-meta">
|
||||
<span>单笔限额 ¥{{ MIN_AMOUNT }} - ¥{{ MAX_AMOUNT }}</span>
|
||||
<button type="button" @click="withdrawForm.amount = availableBalanceCent / 100">
|
||||
全部提现
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div v-if="amountValue > 0" class="amount-preview">
|
||||
<span>预计到账</span>
|
||||
<strong>¥{{ formatMoney(amountValue) }}</strong>
|
||||
</div>
|
||||
|
||||
<van-notice-bar
|
||||
v-if="amountValue > 0 && amountCent > availableBalanceCent"
|
||||
color="#b91c1c"
|
||||
background="#fef2f2"
|
||||
text="余额不足,请调整提现金额"
|
||||
/>
|
||||
|
||||
<van-button
|
||||
block
|
||||
round
|
||||
type="primary"
|
||||
class="submit-btn"
|
||||
:loading="submitting"
|
||||
:disabled="!canWithdraw"
|
||||
loading-text="提交中..."
|
||||
@click="handleSubmit"
|
||||
>
|
||||
提交申请
|
||||
</van-button>
|
||||
</template>
|
||||
</section>
|
||||
|
||||
<section class="records-card">
|
||||
<div class="section-title">
|
||||
<h2>提现记录</h2>
|
||||
<span>{{ withdrawals.length }} 条</span>
|
||||
</div>
|
||||
|
||||
<van-empty v-if="!withdrawals.length && !loading" description="暂无提现记录" />
|
||||
<div v-else class="record-list">
|
||||
<article v-for="item in withdrawals" :key="item.id" class="record-item">
|
||||
<div class="record-top">
|
||||
<div>
|
||||
<strong>¥{{ formatCent(item.amount_cent) }}</strong>
|
||||
<small>{{ item.withdraw_no }}</small>
|
||||
</div>
|
||||
<van-tag :type="statusType(item.status)">{{ statusLabel(item.status) }}</van-tag>
|
||||
</div>
|
||||
<div class="record-meta">
|
||||
<span>{{ accountTypeLabel(item.account_type) }} · {{ item.account_no }}</span>
|
||||
<span>{{ formatDateMinute(item.created_at) }}</span>
|
||||
</div>
|
||||
<p v-if="item.review_remark" class="record-remark">{{ item.review_remark }}</p>
|
||||
<button
|
||||
v-if="item.status === 'pending'"
|
||||
type="button"
|
||||
class="cancel-btn"
|
||||
@click="handleCancel(item)"
|
||||
>
|
||||
取消申请
|
||||
</button>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<van-popup
|
||||
v-model:show="showAccountPopup"
|
||||
round
|
||||
position="bottom"
|
||||
closeable
|
||||
class="account-popup"
|
||||
>
|
||||
<div class="popup-body">
|
||||
<h2>添加收款账号</h2>
|
||||
<van-radio-group v-model="accountForm.account_type" direction="horizontal" class="type-tabs">
|
||||
<van-radio name="alipay">支付宝</van-radio>
|
||||
<van-radio name="wechat">微信</van-radio>
|
||||
<van-radio name="bank">银行卡</van-radio>
|
||||
</van-radio-group>
|
||||
|
||||
<van-field
|
||||
v-model.trim="accountForm.account_name"
|
||||
label="账户名"
|
||||
placeholder="必须与实名认证姓名一致"
|
||||
required
|
||||
/>
|
||||
<van-field
|
||||
v-model.trim="accountForm.account_no"
|
||||
:label="accountForm.account_type === 'bank' ? '银行卡号' : '账号'"
|
||||
:placeholder="
|
||||
accountForm.account_type === 'alipay'
|
||||
? '支付宝账号'
|
||||
: accountForm.account_type === 'wechat'
|
||||
? '微信号'
|
||||
: '银行卡号'
|
||||
"
|
||||
required
|
||||
/>
|
||||
<template v-if="accountForm.account_type === 'bank'">
|
||||
<van-field
|
||||
v-model.trim="accountForm.bank_name"
|
||||
label="银行名称"
|
||||
placeholder="如:中国工商银行"
|
||||
required
|
||||
/>
|
||||
<van-field
|
||||
v-model.trim="accountForm.bank_branch"
|
||||
label="开户支行"
|
||||
placeholder="可选"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<div class="account-tip">
|
||||
账户名必须与实名认证姓名一致;提现将转账到该收款账号,请确认账号信息准确。
|
||||
</div>
|
||||
|
||||
<section class="certificate-section">
|
||||
<div class="certificate-title">
|
||||
<span>收款码/凭证截图</span>
|
||||
<small>最多3张</small>
|
||||
</div>
|
||||
<div class="certificate-grid">
|
||||
<div
|
||||
v-for="(url, index) in accountForm.certificate_urls"
|
||||
:key="url"
|
||||
class="certificate-item"
|
||||
>
|
||||
<img :src="url" alt="收款凭证" />
|
||||
<button type="button" class="certificate-remove" @click="removeCertificate(index)">
|
||||
<van-icon name="cross" :size="13" />
|
||||
</button>
|
||||
</div>
|
||||
<label v-if="accountForm.certificate_urls.length < 3" class="certificate-upload">
|
||||
<input
|
||||
type="file"
|
||||
accept="image/*"
|
||||
:disabled="uploadingCertificate"
|
||||
@change="handleCertificateUpload"
|
||||
/>
|
||||
<van-loading v-if="uploadingCertificate" size="18" color="#ff6a00" />
|
||||
<van-icon v-else name="photograph" :size="22" />
|
||||
<span>{{ uploadingCertificate ? '上传中' : '上传图片' }}</span>
|
||||
</label>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<van-button
|
||||
block
|
||||
round
|
||||
type="primary"
|
||||
:loading="addingAccount"
|
||||
loading-text="添加中..."
|
||||
@click="handleAddAccount"
|
||||
>
|
||||
保存账号
|
||||
</van-button>
|
||||
</div>
|
||||
</van-popup>
|
||||
</main>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.mobile-withdrawal {
|
||||
--van-primary-color: #ff6a00;
|
||||
--van-button-primary-background: #ff6a00;
|
||||
--van-button-primary-border-color: #ff6a00;
|
||||
--van-radio-checked-icon-color: #ff6a00;
|
||||
--van-checkbox-checked-icon-color: #ff6a00;
|
||||
--van-tag-warning-color: #ff6a00;
|
||||
min-height: 100vh;
|
||||
padding: 12px 14px 28px;
|
||||
background: #fff7ed;
|
||||
}
|
||||
|
||||
.page-header {
|
||||
display: grid;
|
||||
grid-template-columns: 40px 1fr 40px;
|
||||
align-items: center;
|
||||
height: 44px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.page-header h1 {
|
||||
margin: 0;
|
||||
text-align: center;
|
||||
font-size: 17px;
|
||||
color: #101828;
|
||||
}
|
||||
|
||||
.back-btn,
|
||||
.refresh-btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border: 0;
|
||||
border-radius: 18px;
|
||||
background: #fff;
|
||||
color: #1f2937;
|
||||
}
|
||||
|
||||
.refresh-btn {
|
||||
justify-self: end;
|
||||
}
|
||||
|
||||
.balance-panel {
|
||||
display: grid;
|
||||
gap: 6px;
|
||||
padding: 18px;
|
||||
border-radius: 8px;
|
||||
background: linear-gradient(135deg, #ff8a1f 0%, #ff5a00 100%);
|
||||
color: #fff;
|
||||
box-shadow: 0 14px 28px rgba(255, 106, 0, 0.22);
|
||||
}
|
||||
|
||||
.balance-panel span,
|
||||
.balance-panel small {
|
||||
color: rgba(255, 255, 255, 0.72);
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.balance-panel strong {
|
||||
font-size: 31px;
|
||||
line-height: 1.1;
|
||||
}
|
||||
|
||||
.withdraw-card,
|
||||
.records-card {
|
||||
margin-top: 12px;
|
||||
padding: 14px;
|
||||
border-radius: 8px;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.section-title h2 {
|
||||
margin: 0;
|
||||
font-size: 16px;
|
||||
color: #101828;
|
||||
}
|
||||
|
||||
.section-title button {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
border: 0;
|
||||
background: transparent;
|
||||
color: #ff6a00;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.section-title span {
|
||||
color: #98a2b3;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.center-loading {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: 28px 0;
|
||||
}
|
||||
|
||||
.empty-state {
|
||||
display: grid;
|
||||
justify-items: center;
|
||||
gap: 10px;
|
||||
padding: 24px 0;
|
||||
color: #98a2b3;
|
||||
}
|
||||
|
||||
.empty-state p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.account-list {
|
||||
display: grid;
|
||||
gap: 8px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.account-option {
|
||||
display: grid;
|
||||
grid-template-columns: 34px 1fr auto 20px;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
width: 100%;
|
||||
min-height: 64px;
|
||||
padding: 10px;
|
||||
border: 1px solid #eaecf0;
|
||||
border-radius: 8px;
|
||||
background: #fff;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.account-option.active {
|
||||
border-color: #ff6a00;
|
||||
background: #fff7ed;
|
||||
}
|
||||
|
||||
.account-icon {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 34px;
|
||||
height: 34px;
|
||||
border-radius: 8px;
|
||||
background: #fff3e8;
|
||||
color: #ff6a00;
|
||||
}
|
||||
|
||||
.account-main {
|
||||
display: grid;
|
||||
gap: 3px;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.account-main strong {
|
||||
overflow: hidden;
|
||||
color: #101828;
|
||||
font-size: 14px;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.account-main small {
|
||||
overflow: hidden;
|
||||
color: #667085;
|
||||
font-size: 12px;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
:deep(.van-cell) {
|
||||
padding-right: 0;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.amount-meta,
|
||||
.amount-preview {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 10px;
|
||||
margin: 10px 0;
|
||||
color: #667085;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.amount-meta button {
|
||||
border: 0;
|
||||
background: transparent;
|
||||
color: #ff6a00;
|
||||
}
|
||||
|
||||
.amount-preview {
|
||||
padding: 10px 12px;
|
||||
border-radius: 8px;
|
||||
background: #f8fafc;
|
||||
}
|
||||
|
||||
.amount-preview strong {
|
||||
color: #ff6a00;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.submit-btn {
|
||||
margin-top: 14px;
|
||||
}
|
||||
|
||||
.record-list {
|
||||
display: grid;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.record-item {
|
||||
padding: 12px;
|
||||
border: 1px solid #eaecf0;
|
||||
border-radius: 8px;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.record-top,
|
||||
.record-meta {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.record-top strong {
|
||||
display: block;
|
||||
color: #101828;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.record-top small,
|
||||
.record-meta {
|
||||
color: #98a2b3;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.record-meta {
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.record-remark {
|
||||
margin: 10px 0 0;
|
||||
color: #b42318;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.cancel-btn {
|
||||
margin-top: 10px;
|
||||
padding: 6px 10px;
|
||||
border: 1px solid #fecdca;
|
||||
border-radius: 999px;
|
||||
background: #fff;
|
||||
color: #b42318;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.account-popup {
|
||||
max-height: 86vh;
|
||||
}
|
||||
|
||||
.popup-body {
|
||||
padding: 20px 16px 24px;
|
||||
}
|
||||
|
||||
.popup-body h2 {
|
||||
margin: 0 0 16px;
|
||||
font-size: 17px;
|
||||
color: #101828;
|
||||
}
|
||||
|
||||
.type-tabs {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.type-tabs :deep(.van-radio__label) {
|
||||
color: #1f2937;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.account-tip {
|
||||
margin: 12px 0;
|
||||
padding: 10px 12px;
|
||||
border-radius: 8px;
|
||||
background: #fffbeb;
|
||||
color: #92400e;
|
||||
font-size: 12px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.certificate-section {
|
||||
margin: 14px 0;
|
||||
}
|
||||
|
||||
.certificate-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 10px;
|
||||
color: #1f2937;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.certificate-title small {
|
||||
color: #98a2b3;
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.certificate-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.certificate-item,
|
||||
.certificate-upload {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
aspect-ratio: 1;
|
||||
border-radius: 8px;
|
||||
background: #fff7ed;
|
||||
}
|
||||
|
||||
.certificate-item {
|
||||
border: 1px solid #fed7aa;
|
||||
}
|
||||
|
||||
.certificate-item img {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.certificate-remove {
|
||||
position: absolute;
|
||||
top: 6px;
|
||||
right: 6px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
border: 0;
|
||||
border-radius: 50%;
|
||||
background: rgba(15, 23, 42, 0.72);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.certificate-upload {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 6px;
|
||||
border: 1px dashed #ff9f43;
|
||||
color: #ff6a00;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.certificate-upload input {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.certificate-upload span {
|
||||
line-height: 1;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user