Files
jurong_circle_frontdesk/src/views/AgentWithdrawals.vue

1099 lines
27 KiB
Vue
Raw Normal View History

2025-08-11 09:40:54 +08:00
<template>
<div class="agent-withdrawals">
<!-- 顶部导航 -->
<div class="page-header">
<button class="btn-back" @click="goBack">
<i class="icon-arrow-left"></i>
返回仪表盘
</button>
<h2 class="page-title">佣金提现</h2>
2025-08-11 09:40:54 +08:00
</div>
<!-- 顶部统计卡片 -->
<div class="stats-cards">
<div class="stat-card">
<div class="stat-icon">
<i class="icon-wallet"></i>
</div>
<div class="stat-content">
<div class="stat-value">¥{{ commissionStats.total_commission || '0.00' }}</div>
<div class="stat-label">总佣金</div>
</div>
</div>
<div class="stat-card">
<div class="stat-icon">
<i class="icon-money"></i>
</div>
<div class="stat-content">
<div class="stat-value">¥{{ commissionStats.available_amount || '0.00' }}</div>
<div class="stat-label">可提现金额</div>
</div>
</div>
<div class="stat-card">
<div class="stat-icon">
<i class="icon-pending"></i>
</div>
<div class="stat-content">
<div class="stat-value">¥{{ commissionStats.pending_withdrawal || '0.00' }}</div>
<div class="stat-label">提现中</div>
</div>
</div>
<div class="stat-card">
<div class="stat-icon">
<i class="icon-success"></i>
</div>
<div class="stat-content">
<div class="stat-value">¥{{ commissionStats.withdrawn_amount || '0.00' }}</div>
<div class="stat-label">已提现</div>
</div>
</div>
</div>
<!-- 提现申请 -->
<div class="withdrawal-section">
<div class="section-header">
<h3>申请提现</h3>
</div>
<form @submit.prevent="submitWithdrawal" class="withdrawal-form">
<div class="form-group">
<label>提现金额</label>
<div class="amount-input">
<input
v-model="withdrawalForm.amount"
type="number"
step="0.01"
min="1"
:max="commissionStats.available_amount"
placeholder="请输入提现金额"
required
>
<span class="currency"></span>
</div>
<div class="amount-info">
<span class="amount-tips">
可提现金额¥{{ commissionStats.available_amount || '0.00' }}
</span>
<button class="btn-edit" @click="openPaymentDialog">
更改收款方式
</button>
2025-08-11 09:40:54 +08:00
</div>
</div>
<div class="form-actions">
<button
type="submit"
class="btn-primary"
:disabled="submitting || !canWithdraw"
>
{{ submitting ? '提交中...' : '申请提现' }}
</button>
</div>
</form>
</div>
<!-- 提现记录 -->
<div class="records-section">
<div class="section-header">
<h3>提现记录</h3>
<div class="filter-controls">
<select v-model="recordsFilter" @change="loadWithdrawalRecords">
<option value="">全部状态</option>
<option value="pending">待审核</option>
<option value="approved">已通过</option>
<option value="completed">已完成</option>
<option value="rejected">已拒绝</option>
</select>
</div>
</div>
<div class="records-list">
<div v-if="loading" class="loading">加载中...</div>
<div v-else-if="withdrawalRecords.length === 0" class="empty">
暂无提现记录
</div>
<div v-else>
<div
v-for="record in withdrawalRecords"
:key="record.id"
class="record-item"
>
<div class="record-header">
<span class="amount">¥{{ record.amount }}</span>
<span class="status" :class="`status-${record.status}`">
{{ getStatusText(record.status) }}
</span>
</div>
<div class="record-details">
<div class="detail-item">
<span class="label">申请时间</span>
<span class="value">{{ formatDate(record.created_at) }}</span>
</div>
<div class="detail-item">
<span class="label">收款信息</span>
<span class="value">
{{ getPaymentTypeText(record.payment_type || 'bank') }}
<template v-if="record.payment_type === 'bank' || !record.payment_type">
- {{ record.bank_name }} {{ maskAccount(record.account_number || record.bank_account) }}
</template>
<template v-else>
- {{ record.account_holder }} ({{ maskAccount(record.account_number) }})
</template>
</span>
</div>
<div v-if="record.admin_note" class="detail-item">
<span class="label">备注</span>
<span class="value">{{ record.admin_note }}</span>
</div>
<div v-if="record.completed_at" class="detail-item">
<span class="label">完成时间</span>
<span class="value">{{ formatDate(record.completed_at) }}</span>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- 编辑收款方式的对话框 -->
<el-dialog
v-model="paymentDialogVisible"
title="编辑收款方式"
width="600px"
:before-close="handleDialogClose"
>
<el-form
ref="paymentFormRef"
:model="paymentForm"
label-width="120px"
label-position="top"
:rules="paymentFormRules"
>
<el-form-item label="收款方式" prop="payment_type">
<el-select
v-model="paymentForm.payment_type"
placeholder="请选择收款方式"
@change="onPaymentTypeChange"
style="width: 100%"
>
<el-option label="银行卡" value="bank"></el-option>
<el-option label="微信收款码" value="wechat"></el-option>
<el-option label="支付宝收款码" value="alipay"></el-option>
<el-option label="云闪付收款码" value="unionpay"></el-option>
</el-select>
</el-form-item>
<el-form-item
v-if="paymentForm.payment_type === 'bank'"
label="银行名称"
prop="bank_name"
>
<el-input
v-model="paymentForm.bank_name"
placeholder="请输入银行名称"
></el-input>
</el-form-item>
<el-form-item
:label="getAccountLabel(paymentForm.payment_type)"
prop="account_number"
>
<el-input
v-model="paymentForm.account_number"
:placeholder="getAccountPlaceholder(paymentForm.payment_type)"
></el-input>
</el-form-item>
<el-form-item
:label="getHolderLabel(paymentForm.payment_type)"
prop="account_holder"
>
<el-input
v-model="paymentForm.account_holder"
:placeholder="getHolderPlaceholder(paymentForm.payment_type)"
></el-input>
</el-form-item>
<el-form-item
v-if="paymentForm.payment_type && paymentForm.payment_type !== 'bank'"
label="收款码图片"
prop="qr_code_url"
>
<el-upload
class="qr-code-uploader"
action="#"
:auto-upload="false"
:show-file-list="false"
:on-change="handleQrCodeUpload"
accept="image/*"
>
<div v-if="paymentForm.qr_code_url" class="qr-code-preview">
<img :src="paymentForm.qr_code_url" class="qr-code-image" />
<div class="qr-code-mask">
<span>点击更换图片</span>
</div>
</div>
<div v-else class="upload-placeholder">
<el-icon class="upload-icon"><Plus /></el-icon>
<div class="upload-text">点击上传收款码</div>
<div class="upload-hint">支持 JPGPNG 格式大小不超过5MB</div>
</div>
</el-upload>
<div v-if="uploadingQrCode" class="upload-progress">
<el-progress :percentage="uploadProgress" :show-text="false"></el-progress>
<span>上传中...</span>
</div>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="paymentDialogVisible = false">取消</el-button>
<el-button
type="primary"
@click="submitPaymentForm"
:loading="updating"
>
保存
</el-button>
</span>
</template>
</el-dialog>
2025-08-11 09:40:54 +08:00
</div>
</template>
<script>
import { ref, reactive, computed, onMounted } from 'vue'
import { useRouter } from 'vue-router'
import { useUserStore } from '@/stores/user'
import { ElMessage, ElMessageBox } from 'element-plus'
import { Plus } from '@element-plus/icons-vue'
2025-08-11 09:40:54 +08:00
import api from '@/utils/api'
export default {
name: 'AgentWithdrawals',
components: {
Plus
},
2025-08-11 09:40:54 +08:00
setup() {
const router = useRouter()
const userStore = useUserStore()
const paymentFormRef = ref(null)
2025-08-11 09:40:54 +08:00
// 响应式数据
const loading = ref(false)
const updating = ref(false)
const submitting = ref(false)
const paymentDialogVisible = ref(false)
2025-08-11 09:40:54 +08:00
const recordsFilter = ref('')
const uploadingQrCode = ref(false)
const uploadProgress = ref(0)
2025-08-11 09:40:54 +08:00
const commissionStats = reactive({
total_commission: '0.00',
available_amount: '0.00',
pending_withdrawal: '0.00',
withdrawn_amount: '0.00'
})
const paymentInfo = reactive({
payment_type: '',
bank_name: '',
account_number: '',
account_holder: '',
qr_code_url: ''
})
2025-08-11 09:40:54 +08:00
const paymentForm = reactive({
payment_type: '',
bank_name: '',
account_number: '',
account_holder: '',
qr_code_url: ''
})
const withdrawalForm = reactive({
amount: ''
})
const withdrawalRecords = ref([])
// 表单验证规则
const paymentFormRules = reactive({
payment_type: [
{ required: true, message: '请选择收款方式', trigger: 'change' }
],
bank_name: [
{ required: true, message: '请输入银行名称', trigger: 'blur' }
],
account_number: [
{ required: true, message: '请输入账号', trigger: 'blur' }
],
account_holder: [
{ required: true, message: '请输入持有人姓名', trigger: 'blur' }
],
qr_code_url: [
{ required: true, message: '请上传收款码图片', trigger: 'change' }
]
})
2025-08-11 09:40:54 +08:00
// 计算属性
const canWithdraw = computed(() => {
const amount = parseFloat(withdrawalForm.amount)
const available = parseFloat(commissionStats.available_amount)
const hasBasicInfo = amount > 0 && amount <= available && paymentInfo.account_number && paymentInfo.payment_type
// 银行卡只需要基本信息
if (paymentInfo.payment_type === 'bank') {
return hasBasicInfo
}
// 收款码需要额外验证图片
return hasBasicInfo && paymentInfo.qr_code_url
})
// 方法
/**
* 加载佣金统计数据
*/
const loadCommissionStats = async () => {
try {
const response = await api.get('/agent-withdrawals/stats')
if (response.data.success) {
// 更新佣金统计数据
Object.assign(commissionStats, {
total_commission: response.data.data.total_commission || '0.00',
available_amount: response.data.data.available_amount || '0.00',
pending_withdrawal: response.data.data.pending_withdrawal || '0.00',
withdrawn_amount: response.data.data.withdrawn_amount || '0.00'
})
// 处理收款方式信息
if (response.data.data.paymentInfo) {
Object.assign(paymentInfo, response.data.data.paymentInfo)
Object.assign(paymentForm, response.data.data.paymentInfo)
} else if (response.data.data.bank_account) {
// 兼容旧的银行信息字段
const bankInfo = {
payment_type: 'bank',
bank_name: response.data.data.bank_name || '',
account_number: response.data.data.bank_account || '',
account_holder: response.data.data.account_holder || '',
qr_code_url: ''
}
Object.assign(paymentInfo, bankInfo)
Object.assign(paymentForm, bankInfo)
}
}
} catch (error) {
console.error('加载佣金统计失败:', error)
ElMessage.error('加载佣金统计失败')
2025-08-11 09:40:54 +08:00
}
}
/**
* 打开收款方式对话框
2025-08-11 09:40:54 +08:00
*/
const openPaymentDialog = () => {
// 重置表单为当前信息
Object.assign(paymentForm, paymentInfo)
paymentDialogVisible.value = true
}
/**
* 提交收款方式表单
*/
const submitPaymentForm = () => {
paymentFormRef.value.validate(async (valid) => {
if (!valid) return
if (updating.value) return
updating.value = true
try {
const response = await api.put('/agent-withdrawals/payment-info', paymentForm)
if (response.data.success) {
Object.assign(paymentInfo, paymentForm)
paymentDialogVisible.value = false
ElMessage.success('收款方式更新成功')
} else {
ElMessage.error(response.data.message || '更新失败')
}
} catch (error) {
console.error('更新收款方式失败:', error)
ElMessage.error('更新失败,请重试')
} finally {
updating.value = false
2025-08-11 09:40:54 +08:00
}
})
}
/**
* 处理对话框关闭
*/
const handleDialogClose = (done) => {
if (JSON.stringify(paymentForm) !== JSON.stringify(paymentInfo)) {
ElMessageBox.confirm('您有未保存的更改,确定要关闭吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
done()
}).catch(() => {})
} else {
done()
2025-08-11 09:40:54 +08:00
}
}
/**
* 提交提现申请
*/
const submitWithdrawal = async () => {
if (submitting.value || !canWithdraw.value) return
if (!paymentInfo.account_number || !paymentInfo.payment_type) {
ElMessage.warning('请先设置收款方式')
return
}
2025-08-11 09:40:54 +08:00
// 收款码类型需要验证图片
if (paymentInfo.payment_type !== 'bank' && !paymentInfo.qr_code_url) {
ElMessage.warning('请上传收款码图片')
return
}
2025-08-11 09:40:54 +08:00
submitting.value = true
try {
const response = await api.post('/agent-withdrawals/apply', {
amount: parseFloat(withdrawalForm.amount)
})
if (response.data.success) {
ElMessage.success('提现申请提交成功,请等待审核')
2025-08-11 09:40:54 +08:00
withdrawalForm.amount = ''
await loadCommissionStats()
await loadWithdrawalRecords()
} else {
ElMessage.error(response.data.message || '申请失败')
2025-08-11 09:40:54 +08:00
}
} catch (error) {
console.error('提现申请失败:', error)
ElMessage.error('申请失败,请重试')
2025-08-11 09:40:54 +08:00
} finally {
submitting.value = false
}
}
/**
* 加载提现记录
*/
const loadWithdrawalRecords = async () => {
loading.value = true
try {
const params = {}
if (recordsFilter.value) {
params.status = recordsFilter.value
}
const response = await api.get('/agent-withdrawals/records', { params })
if (response.data.success) {
withdrawalRecords.value = response.data.data.records || []
}
} catch (error) {
console.error('加载提现记录失败:', error)
ElMessage.error('加载提现记录失败')
2025-08-11 09:40:54 +08:00
} finally {
loading.value = false
}
}
/**
* 格式化日期
*/
const formatDate = (dateString) => {
if (!dateString) return ''
const date = new Date(dateString)
return date.toLocaleString('zh-CN')
}
/**
* 获取状态文本
*/
const getStatusText = (status) => {
const statusMap = {
pending: '待审核',
approved: '已通过',
completed: '已完成',
rejected: '已拒绝'
}
return statusMap[status] || status
}
/**
* 掩码显示账号信息
*/
const maskAccount = (account) => {
if (!account) return ''
if (account.length <= 8) return account
return account.slice(0, 4) + '****' + account.slice(-4)
}
/**
* 处理收款码图片上传
*/
const handleQrCodeUpload = async (file) => {
2025-08-11 09:40:54 +08:00
// 验证文件类型
if (!file.raw.type.startsWith('image/')) {
ElMessage.error('请选择图片文件')
return false
2025-08-11 09:40:54 +08:00
}
// 验证文件大小限制为5MB
if (file.raw.size > 5 * 1024 * 1024) {
ElMessage.error('图片大小不能超过5MB')
return false
2025-08-11 09:40:54 +08:00
}
uploadingQrCode.value = true
uploadProgress.value = 0
2025-08-11 09:40:54 +08:00
try {
const formData = new FormData()
formData.append('qrCode', file.raw)
2025-08-11 09:40:54 +08:00
const response = await api.post('/agent-withdrawals/upload-qr-code', formData, {
headers: {
'Content-Type': 'multipart/form-data'
},
onUploadProgress: (progressEvent) => {
if (progressEvent.total) {
uploadProgress.value = Math.round((progressEvent.loaded * 100) / progressEvent.total)
}
2025-08-11 09:40:54 +08:00
}
})
if (response.data.success) {
paymentForm.qr_code_url = response.data.data.url
ElMessage.success('上传成功')
2025-08-11 09:40:54 +08:00
} else {
ElMessage.error(response.data.message || '上传失败')
2025-08-11 09:40:54 +08:00
}
} catch (error) {
console.error('上传收款码失败:', error)
ElMessage.error('上传失败,请重试')
2025-08-11 09:40:54 +08:00
} finally {
uploadingQrCode.value = false
uploadProgress.value = 0
2025-08-11 09:40:54 +08:00
}
}
/**
* 获取收款方式显示文本
*/
const getPaymentTypeText = (type) => {
const types = {
'bank': '银行卡',
'wechat': '微信收款码',
'alipay': '支付宝收款码',
'unionpay': '云闪付收款码'
}
return types[type] || ''
}
/**
* 获取账号标签
*/
const getAccountLabel = (type) => {
const labels = {
'bank': '银行账号',
'wechat': '微信号',
'alipay': '支付宝账号',
'unionpay': '云闪付账号'
}
return labels[type] || '账号'
}
/**
* 获取持有人标签
*/
const getHolderLabel = (type) => {
const labels = {
'bank': '开户人',
'wechat': '微信昵称',
'alipay': '支付宝昵称',
'unionpay': '云闪付昵称'
}
return labels[type] || '持有人'
}
/**
* 获取账号输入占位符
*/
const getAccountPlaceholder = (type) => {
const placeholders = {
'bank': '请输入银行账号',
'wechat': '请输入微信号',
'alipay': '请输入支付宝账号',
'unionpay': '请输入云闪付账号'
}
return placeholders[type] || '请输入账号'
}
/**
* 获取持有人输入占位符
*/
const getHolderPlaceholder = (type) => {
const placeholders = {
'bank': '请输入开户人姓名',
'wechat': '请输入微信昵称',
'alipay': '请输入支付宝昵称',
'unionpay': '请输入云闪付昵称'
}
return placeholders[type] || '请输入持有人姓名'
}
/**
* 收款方式类型改变时的处理
*/
const onPaymentTypeChange = () => {
// 清空非通用字段
if (paymentForm.payment_type !== 'bank') {
paymentForm.bank_name = ''
} else {
paymentForm.qr_code_url = ''
}
// 重置验证状态
nextTick(() => {
paymentFormRef.value.clearValidate(['bank_name', 'qr_code_url'])
})
2025-08-11 09:40:54 +08:00
}
/**
* 返回代理仪表盘
*/
const goBack = () => {
router.push('/agent/dashboard')
}
// 生命周期
onMounted(async () => {
await loadCommissionStats()
await loadWithdrawalRecords()
})
return {
// 引用
paymentFormRef,
// 状态
2025-08-11 09:40:54 +08:00
loading,
updating,
submitting,
paymentDialogVisible,
2025-08-11 09:40:54 +08:00
recordsFilter,
uploadingQrCode,
uploadProgress,
// 数据
2025-08-11 09:40:54 +08:00
commissionStats,
paymentInfo,
paymentForm,
withdrawalForm,
withdrawalRecords,
// 计算属性
2025-08-11 09:40:54 +08:00
canWithdraw,
// 方法
2025-08-11 09:40:54 +08:00
loadCommissionStats,
openPaymentDialog,
submitPaymentForm,
handleDialogClose,
2025-08-11 09:40:54 +08:00
submitWithdrawal,
loadWithdrawalRecords,
formatDate,
getStatusText,
maskAccount,
handleQrCodeUpload,
getPaymentTypeText,
getAccountLabel,
getHolderLabel,
getAccountPlaceholder,
getHolderPlaceholder,
onPaymentTypeChange,
goBack,
// 表单规则
paymentFormRules
2025-08-11 09:40:54 +08:00
}
}
}
</script>
<style scoped>
.agent-withdrawals {
padding: 20px;
max-width: 1200px;
margin: 0 auto;
background: linear-gradient(to bottom, #72c9ffae, #f3f3f3);
2025-08-11 09:40:54 +08:00
}
/* 页面头部 */
.page-header {
display: flex;
align-items: center;
position: relative;
2025-08-11 09:40:54 +08:00
margin-bottom: 24px;
padding-bottom: 16px;
border-bottom: 1px solid #eee;
}
.page-title {
position: absolute;
left: 50%;
transform: translateX(-50%);
2025-08-11 09:40:54 +08:00
margin: 0;
font-size: 24px;
color: white;
2025-08-11 09:40:54 +08:00
font-weight: 600;
}
/* 返回按钮 */
.btn-back {
gap: 8px;
padding: 10px 16px;
background: none;
border: none;
2025-08-11 09:40:54 +08:00
border-radius: 8px;
font-size: 14px;
color: white;
2025-08-11 09:40:54 +08:00
cursor: pointer;
}
.btn-back:hover {
border-color: #adb5bd;
}
.btn-back .icon-arrow-left::before {
content: '<';
2025-08-11 09:40:54 +08:00
font-size: 16px;
}
/* 统计卡片 */
.stats-cards {
display: grid;
grid-template-columns: repeat(2, 1fr);
2025-08-11 09:40:54 +08:00
gap: 20px;
margin-bottom: 30px;
width: 343px;
2025-08-11 09:40:54 +08:00
}
.stat-card {
border-radius: 12px;
padding: 24px;
display: flex;
align-items: center;
gap: 16px;
}
.stat-icon {
width: 48px;
height: 48px;
border-radius: 12px;
display: flex;
align-items: center;
justify-content: center;
font-size: 24px;
color: white;
}
.stat-card:nth-child(1) .stat-icon {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}
.stat-card:nth-child(2) .stat-icon {
background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
}
.stat-card:nth-child(3) .stat-icon {
background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
}
.stat-card:nth-child(4) .stat-icon {
background: linear-gradient(135deg, #43e97b 0%, #38f9d7 100%);
}
.stat-content {
flex: 1;
}
.stat-value {
font-size: 24px;
font-weight: bold;
color: #333;
margin-bottom: 4px;
}
.stat-label {
font-size: 14px;
color: #666;
}
/* 通用区块样式 */
.withdrawal-section,
.records-section {
border-radius: 12px;
padding: 24px;
margin: 0 auto 20px;
2025-08-11 09:40:54 +08:00
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
width: 343px;
2025-08-11 09:40:54 +08:00
}
.section-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
padding-bottom: 12px;
}
.section-header h3 {
margin: 0;
font-size: 18px;
color: #333;
line-height: 24px;
2025-08-11 09:40:54 +08:00
}
/* 表单样式 */
.withdrawal-form {
display: grid;
gap: 20px;
}
.form-group {
2025-08-11 09:40:54 +08:00
display: grid;
gap: 8px;
}
.form-group label {
2025-08-11 09:40:54 +08:00
font-size: 14px;
color: #333;
2025-08-11 09:40:54 +08:00
font-weight: 500;
}
.amount-info {
display: flex;
justify-content: space-between;
align-items: center;
2025-08-11 09:40:54 +08:00
}
.amount-input {
2025-08-11 09:40:54 +08:00
position: relative;
display: flex;
align-items: center;
width: 100%;
2025-08-11 09:40:54 +08:00
}
.amount-input input {
width: 100%;
2025-08-11 09:40:54 +08:00
padding: 12px;
border: 1px solid #ddd;
border-radius: 8px;
font-size: 14px;
transition: border-color 0.3s;
padding-right: 40px;
2025-08-11 09:40:54 +08:00
}
.amount-input input:focus {
2025-08-11 09:40:54 +08:00
outline: none;
border-color: #007bff;
}
.currency {
position: absolute;
right: 12px;
color: #666;
font-size: 14px;
}
.amount-tips {
font-size: 12px;
color: #666;
margin-right: 10px;
2025-08-11 09:40:54 +08:00
}
.form-actions {
display: flex;
justify-content: center; /* 将右对齐改为居中对齐 */
2025-08-11 09:40:54 +08:00
}
/* 按钮样式 */
.btn-primary,
.btn-edit {
padding: 10px 20px;
border: none;
border-radius: 1000px;
2025-08-11 09:40:54 +08:00
font-size: 14px;
cursor: pointer;
transition: all 0.3s;
}
.btn-primary {
background: #007bff;
color: white;
width: 300px;
/* 保持申请提现按钮原有样式不变 */
2025-08-11 09:40:54 +08:00
}
.btn-primary:hover:not(:disabled) {
background: #0056b3;
}
.btn-primary:disabled {
background: #ccc;
cursor: not-allowed;
}
.btn-edit {
background: #28a745;
color: white;
padding: 8px 16px;
font-size: 12px;
white-space: nowrap;
2025-08-11 09:40:54 +08:00
}
.btn-edit:hover {
background: #1e7e34;
}
/* 筛选控件 */
.filter-controls {
height: 24px;
display: flex;
align-items: center;
}
2025-08-11 09:40:54 +08:00
.filter-controls select {
padding: 4px 8px;
2025-08-11 09:40:54 +08:00
border: 1px solid #ddd;
border-radius: 6px;
font-size: 14px;
height: 24px;
2025-08-11 09:40:54 +08:00
}
/* 记录列表 */
.records-list {
display: grid;
gap: 16px;
}
.loading,
.empty {
text-align: center;
padding: 40px;
color: #666;
font-size: 14px;
}
.record-item {
border: 1px solid black;
2025-08-11 09:40:54 +08:00
border-radius: 8px;
padding: 16px;
transition: box-shadow 0.3s;
}
.record-item:hover {
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.record-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 12px;
}
.record-header .amount {
font-size: 18px;
font-weight: bold;
color: #333;
}
.status {
padding: 4px 12px;
border-radius: 20px;
font-size: 12px;
font-weight: 500;
}
.status-pending {
background: #fff3cd;
color: #856404;
}
.status-approved {
background: #d1ecf1;
color: #0c5460;
}
.status-completed {
background: #d4edda;
color: #155724;
}
.status-rejected {
background: #f8d7da;
color: #721c24;
}
.record-details {
display: grid;
gap: 8px;
}
.detail-item {
display: flex;
font-size: 14px;
}
.detail-item .label {
width: 80px;
color: #666;
flex-shrink: 0;
}
.detail-item .value {
color: #333;
flex: 1;
}
/* 图标 */
.icon-wallet::before { content: '💰'; }
.icon-money::before { content: '💵'; }
.icon-pending::before { content: '⏳'; }
.icon-success::before { content: '✅'; }
/* 响应式设计 */
@media (max-width: 768px) {
.agent-withdrawals {
padding: 16px;
}
.stat-card {
padding: 20px;
}
.section-header {
flex-direction: column;
align-items: flex-start;
gap: 12px;
}
.record-header {
flex-direction: column;
align-items: flex-start;
gap: 8px;
}
}
2025-08-11 09:40:54 +08:00
</style>