Initial commit: One Pipe System
完整的管理系统,包含账户管理、卡片管理、套餐管理、财务管理等功能模块。 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
210
src/views/finance/customer-account/index.vue
Normal file
210
src/views/finance/customer-account/index.vue
Normal file
@@ -0,0 +1,210 @@
|
||||
<template>
|
||||
<div class="page-content">
|
||||
<ElCard shadow="never">
|
||||
<!-- 搜索栏 -->
|
||||
<ElForm :inline="true" :model="searchForm" class="search-form">
|
||||
<ElFormItem label="客户账号">
|
||||
<ElInput v-model="searchForm.accountNo" placeholder="请输入客户账号" clearable style="width: 200px" />
|
||||
</ElFormItem>
|
||||
<ElFormItem label="客户名称">
|
||||
<ElInput v-model="searchForm.customerName" placeholder="请输入客户名称" clearable style="width: 200px" />
|
||||
</ElFormItem>
|
||||
<ElFormItem label="客户类型">
|
||||
<ElSelect v-model="searchForm.customerType" placeholder="请选择" clearable style="width: 150px">
|
||||
<ElOption label="代理商" value="agent" />
|
||||
<ElOption label="企业客户" value="enterprise" />
|
||||
</ElSelect>
|
||||
</ElFormItem>
|
||||
<ElFormItem>
|
||||
<ElButton type="primary" @click="handleSearch">查询</ElButton>
|
||||
<ElButton @click="handleReset">重置</ElButton>
|
||||
</ElFormItem>
|
||||
</ElForm>
|
||||
|
||||
<!-- 数据表格 -->
|
||||
<ArtTable :data="tableData" index stripe>
|
||||
<template #default>
|
||||
<ElTableColumn label="客户账号" prop="accountNo" min-width="150" />
|
||||
<ElTableColumn label="客户名称" prop="customerName" min-width="150" />
|
||||
<ElTableColumn label="客户类型" prop="customerType" width="120">
|
||||
<template #default="scope">
|
||||
<ElTag :type="scope.row.customerType === 'agent' ? 'success' : 'primary'">
|
||||
{{ scope.row.customerType === 'agent' ? '代理商' : '企业客户' }}
|
||||
</ElTag>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="佣金总额" prop="totalCommission" width="150">
|
||||
<template #default="scope"> ¥{{ scope.row.totalCommission.toFixed(2) }} </template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="可提现金额" prop="availableAmount" width="150">
|
||||
<template #default="scope">
|
||||
<span style="color: var(--el-color-success)"> ¥{{ scope.row.availableAmount.toFixed(2) }} </span>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="待入账金额" prop="pendingAmount" width="150">
|
||||
<template #default="scope">
|
||||
<span style="color: var(--el-color-warning)"> ¥{{ scope.row.pendingAmount.toFixed(2) }} </span>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="已提现金额" prop="withdrawnAmount" width="150">
|
||||
<template #default="scope"> ¥{{ scope.row.withdrawnAmount.toFixed(2) }} </template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="提现次数" prop="withdrawCount" width="100" />
|
||||
<ElTableColumn label="最后提现时间" prop="lastWithdrawTime" width="180" />
|
||||
<ElTableColumn label="操作" width="180" fixed="right">
|
||||
<template #default="scope">
|
||||
<ElButton link type="primary" @click="handleViewDetail(scope.row)">查看详情</ElButton>
|
||||
<ElButton link type="primary" @click="handleViewFlow(scope.row)">流水记录</ElButton>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
</template>
|
||||
</ArtTable>
|
||||
|
||||
<!-- 分页 -->
|
||||
<ElPagination
|
||||
v-model:current-page="pagination.page"
|
||||
v-model:page-size="pagination.pageSize"
|
||||
:total="pagination.total"
|
||||
:page-sizes="[10, 20, 50, 100]"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
style="margin-top: 20px; justify-content: flex-end"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
/>
|
||||
</ElCard>
|
||||
|
||||
<!-- 详情对话框 -->
|
||||
<ElDialog v-model="detailDialogVisible" title="客户账号详情" width="800px" align-center>
|
||||
<ElDescriptions :column="2" border>
|
||||
<ElDescriptionsItem label="客户账号">{{ currentRow?.accountNo }}</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="客户名称">{{ currentRow?.customerName }}</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="客户类型">
|
||||
<ElTag :type="currentRow?.customerType === 'agent' ? 'success' : 'primary'">
|
||||
{{ currentRow?.customerType === 'agent' ? '代理商' : '企业客户' }}
|
||||
</ElTag>
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="联系电话">{{ currentRow?.phone }}</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="佣金总额">¥{{ currentRow?.totalCommission.toFixed(2) }}</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="可提现金额">
|
||||
<span style="color: var(--el-color-success)"> ¥{{ currentRow?.availableAmount.toFixed(2) }} </span>
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="待入账金额">
|
||||
<span style="color: var(--el-color-warning)"> ¥{{ currentRow?.pendingAmount.toFixed(2) }} </span>
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="已提现金额">¥{{ currentRow?.withdrawnAmount.toFixed(2) }}</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="提现次数">{{ currentRow?.withdrawCount }}</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="最后提现时间">{{ currentRow?.lastWithdrawTime }}</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="注册时间">{{ currentRow?.createTime }}</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="备注" :span="2">{{ currentRow?.remark || '无' }}</ElDescriptionsItem>
|
||||
</ElDescriptions>
|
||||
</ElDialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ElMessage } from 'element-plus'
|
||||
|
||||
defineOptions({ name: 'CustomerAccount' })
|
||||
|
||||
const searchForm = reactive({
|
||||
accountNo: '',
|
||||
customerName: '',
|
||||
customerType: ''
|
||||
})
|
||||
|
||||
const pagination = reactive({
|
||||
page: 1,
|
||||
pageSize: 20,
|
||||
total: 100
|
||||
})
|
||||
|
||||
const detailDialogVisible = ref(false)
|
||||
const currentRow = ref<any>(null)
|
||||
|
||||
// 模拟表格数据
|
||||
const tableData = ref([
|
||||
{
|
||||
id: '1',
|
||||
accountNo: 'ACC20260001',
|
||||
customerName: '深圳市科技有限公司',
|
||||
customerType: 'agent',
|
||||
phone: '13800138000',
|
||||
totalCommission: 158900.5,
|
||||
availableAmount: 58900.5,
|
||||
pendingAmount: 50000.0,
|
||||
withdrawnAmount: 50000.0,
|
||||
withdrawCount: 12,
|
||||
lastWithdrawTime: '2026-01-08 15:00:00',
|
||||
createTime: '2025-06-01 10:00:00',
|
||||
remark: '优质代理商'
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
accountNo: 'ACC20260002',
|
||||
customerName: '广州智能设备公司',
|
||||
customerType: 'enterprise',
|
||||
phone: '13900139000',
|
||||
totalCommission: 89600.0,
|
||||
availableAmount: 35600.0,
|
||||
pendingAmount: 24000.0,
|
||||
withdrawnAmount: 30000.0,
|
||||
withdrawCount: 8,
|
||||
lastWithdrawTime: '2026-01-05 10:30:00',
|
||||
createTime: '2025-07-15 14:20:00',
|
||||
remark: ''
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
accountNo: 'ACC20260003',
|
||||
customerName: '北京物联网代理',
|
||||
customerType: 'agent',
|
||||
phone: '13700137000',
|
||||
totalCommission: 256700.0,
|
||||
availableAmount: 106700.0,
|
||||
pendingAmount: 80000.0,
|
||||
withdrawnAmount: 70000.0,
|
||||
withdrawCount: 15,
|
||||
lastWithdrawTime: '2026-01-09 09:15:00',
|
||||
createTime: '2025-05-10 09:00:00',
|
||||
remark: '金牌代理商'
|
||||
}
|
||||
])
|
||||
|
||||
const handleSearch = () => {
|
||||
ElMessage.success('查询成功')
|
||||
}
|
||||
|
||||
const handleReset = () => {
|
||||
searchForm.accountNo = ''
|
||||
searchForm.customerName = ''
|
||||
searchForm.customerType = ''
|
||||
ElMessage.info('已重置')
|
||||
}
|
||||
|
||||
const handleViewDetail = (row: any) => {
|
||||
currentRow.value = row
|
||||
detailDialogVisible.value = true
|
||||
}
|
||||
|
||||
const handleViewFlow = (row: any) => {
|
||||
ElMessage.info(`查看 ${row.customerName} 的流水记录`)
|
||||
}
|
||||
|
||||
const handleSizeChange = (size: number) => {
|
||||
pagination.pageSize = size
|
||||
ElMessage.info(`每页显示 ${size} 条`)
|
||||
}
|
||||
|
||||
const handleCurrentChange = (page: number) => {
|
||||
pagination.page = page
|
||||
ElMessage.info(`当前第 ${page} 页`)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.page-content {
|
||||
.search-form {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
305
src/views/finance/my-account/index.vue
Normal file
305
src/views/finance/my-account/index.vue
Normal file
@@ -0,0 +1,305 @@
|
||||
<template>
|
||||
<div class="page-content">
|
||||
<!-- 统计卡片 -->
|
||||
<ElRow :gutter="20" style="margin-bottom: 20px">
|
||||
<ElCol :xs="24" :sm="12" :lg="6">
|
||||
<ElCard shadow="hover">
|
||||
<div class="stat-card">
|
||||
<div class="stat-icon" style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%)">
|
||||
<i class="iconfont-sys"></i>
|
||||
</div>
|
||||
<div class="stat-content">
|
||||
<div class="stat-label">佣金总额</div>
|
||||
<div class="stat-value">¥{{ accountInfo.totalCommission.toFixed(2) }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</ElCard>
|
||||
</ElCol>
|
||||
<ElCol :xs="24" :sm="12" :lg="6">
|
||||
<ElCard shadow="hover">
|
||||
<div class="stat-card">
|
||||
<div class="stat-icon" style="background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%)">
|
||||
<i class="iconfont-sys"></i>
|
||||
</div>
|
||||
<div class="stat-content">
|
||||
<div class="stat-label">可提现金额</div>
|
||||
<div class="stat-value">¥{{ accountInfo.availableAmount.toFixed(2) }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</ElCard>
|
||||
</ElCol>
|
||||
<ElCol :xs="24" :sm="12" :lg="6">
|
||||
<ElCard shadow="hover">
|
||||
<div class="stat-card">
|
||||
<div class="stat-icon" style="background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%)">
|
||||
<i class="iconfont-sys"></i>
|
||||
</div>
|
||||
<div class="stat-content">
|
||||
<div class="stat-label">待入账金额</div>
|
||||
<div class="stat-value">¥{{ accountInfo.pendingAmount.toFixed(2) }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</ElCard>
|
||||
</ElCol>
|
||||
<ElCol :xs="24" :sm="12" :lg="6">
|
||||
<ElCard shadow="hover">
|
||||
<div class="stat-card">
|
||||
<div class="stat-icon" style="background: linear-gradient(135deg, #fa709a 0%, #fee140 100%)">
|
||||
<i class="iconfont-sys"></i>
|
||||
</div>
|
||||
<div class="stat-content">
|
||||
<div class="stat-label">已提现金额</div>
|
||||
<div class="stat-value">¥{{ accountInfo.withdrawnAmount.toFixed(2) }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</ElCard>
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
|
||||
<!-- 操作按钮 -->
|
||||
<ElRow style="margin-bottom: 20px">
|
||||
<ElButton type="primary" @click="showWithdrawDialog">申请提现</ElButton>
|
||||
<ElButton @click="viewWithdrawHistory">提现记录</ElButton>
|
||||
</ElRow>
|
||||
|
||||
<!-- 收支流水 -->
|
||||
<ElCard shadow="never">
|
||||
<template #header>
|
||||
<div style="display: flex; justify-content: space-between; align-items: center">
|
||||
<span style="font-weight: 500">收支流水</span>
|
||||
<ElRadioGroup v-model="flowType" size="small">
|
||||
<ElRadioButton value="all">全部</ElRadioButton>
|
||||
<ElRadioButton value="income">收入</ElRadioButton>
|
||||
<ElRadioButton value="withdraw">提现</ElRadioButton>
|
||||
</ElRadioGroup>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<ArtTable :data="filteredFlowData" index max-height="500">
|
||||
<template #default>
|
||||
<ElTableColumn label="流水号" prop="flowNo" min-width="180" />
|
||||
<ElTableColumn label="类型" prop="type">
|
||||
<template #default="scope">
|
||||
<ElTag :type="scope.row.type === 'income' ? 'success' : 'warning'">
|
||||
{{ scope.row.type === 'income' ? '收入' : '提现' }}
|
||||
</ElTag>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="金额" prop="amount">
|
||||
<template #default="scope">
|
||||
<span :style="{ color: scope.row.type === 'income' ? 'var(--el-color-success)' : 'var(--el-color-danger)' }">
|
||||
{{ scope.row.type === 'income' ? '+' : '-' }}¥{{ scope.row.amount.toFixed(2) }}
|
||||
</span>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="余额" prop="balance">
|
||||
<template #default="scope"> ¥{{ scope.row.balance.toFixed(2) }} </template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="说明" prop="description" show-overflow-tooltip />
|
||||
<ElTableColumn label="时间" prop="createTime" width="180" />
|
||||
</template>
|
||||
</ArtTable>
|
||||
</ElCard>
|
||||
|
||||
<!-- 提现申请对话框 -->
|
||||
<ElDialog v-model="withdrawDialogVisible" title="申请提现" width="600px" align-center>
|
||||
<ElForm ref="withdrawFormRef" :model="withdrawForm" :rules="withdrawRules" label-width="120px">
|
||||
<ElFormItem label="可提现金额">
|
||||
<span style="color: var(--el-color-success); font-size: 20px; font-weight: 500">
|
||||
¥{{ accountInfo.availableAmount.toFixed(2) }}
|
||||
</span>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="提现金额" prop="amount">
|
||||
<ElInputNumber
|
||||
v-model="withdrawForm.amount"
|
||||
:min="1"
|
||||
:max="accountInfo.availableAmount"
|
||||
:precision="2"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="手续费">
|
||||
<span>¥{{ calculatedFee.toFixed(2) }}</span>
|
||||
<span style="margin-left: 8px; color: var(--el-text-color-secondary)">
|
||||
(费率: {{ feeRate * 100 }}%)
|
||||
</span>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="实际到账">
|
||||
<span style="color: var(--el-color-success); font-size: 18px; font-weight: 500">
|
||||
¥{{ actualAmount.toFixed(2) }}
|
||||
</span>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="收款银行" prop="bankName">
|
||||
<ElSelect v-model="withdrawForm.bankName" placeholder="请选择收款银行" style="width: 100%">
|
||||
<ElOption label="中国工商银行" value="工商银行" />
|
||||
<ElOption label="中国建设银行" value="建设银行" />
|
||||
<ElOption label="中国农业银行" value="农业银行" />
|
||||
<ElOption label="中国银行" value="中国银行" />
|
||||
<ElOption label="招商银行" value="招商银行" />
|
||||
</ElSelect>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="银行账户" prop="bankAccount">
|
||||
<ElInput v-model="withdrawForm.bankAccount" placeholder="请输入银行账户" />
|
||||
</ElFormItem>
|
||||
<ElFormItem label="开户姓名" prop="accountName">
|
||||
<ElInput v-model="withdrawForm.accountName" placeholder="请输入开户姓名" />
|
||||
</ElFormItem>
|
||||
</ElForm>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<ElButton @click="withdrawDialogVisible = false">取消</ElButton>
|
||||
<ElButton type="primary" @click="submitWithdraw">提交申请</ElButton>
|
||||
</div>
|
||||
</template>
|
||||
</ElDialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ElMessage } from 'element-plus'
|
||||
import type { FormInstance, FormRules } from 'element-plus'
|
||||
|
||||
defineOptions({ name: 'MyAccount' })
|
||||
|
||||
const accountInfo = reactive({
|
||||
totalCommission: 158900.5,
|
||||
availableAmount: 58900.5,
|
||||
pendingAmount: 50000.0,
|
||||
withdrawnAmount: 50000.0
|
||||
})
|
||||
|
||||
const flowType = ref('all')
|
||||
const withdrawDialogVisible = ref(false)
|
||||
const withdrawFormRef = ref<FormInstance>()
|
||||
const feeRate = 0.002 // 手续费率 0.2%
|
||||
|
||||
const withdrawForm = reactive({
|
||||
amount: 0,
|
||||
bankName: '',
|
||||
bankAccount: '',
|
||||
accountName: ''
|
||||
})
|
||||
|
||||
const withdrawRules = reactive<FormRules>({
|
||||
amount: [
|
||||
{ required: true, message: '请输入提现金额', trigger: 'blur' },
|
||||
{
|
||||
validator: (rule, value, callback) => {
|
||||
if (value > accountInfo.availableAmount) {
|
||||
callback(new Error('提现金额不能大于可提现金额'))
|
||||
} else if (value < 1) {
|
||||
callback(new Error('提现金额不能小于1元'))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
},
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
bankName: [{ required: true, message: '请选择收款银行', trigger: 'change' }],
|
||||
bankAccount: [{ required: true, message: '请输入银行账户', trigger: 'blur' }],
|
||||
accountName: [{ required: true, message: '请输入开户姓名', trigger: 'blur' }]
|
||||
})
|
||||
|
||||
const flowData = ref([
|
||||
{
|
||||
id: '1',
|
||||
flowNo: 'FL202601090001',
|
||||
type: 'income',
|
||||
amount: 1580.0,
|
||||
balance: 58900.5,
|
||||
description: '套餐销售佣金',
|
||||
createTime: '2026-01-09 10:30:00'
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
flowNo: 'FL202601080001',
|
||||
type: 'withdraw',
|
||||
amount: 5000.0,
|
||||
balance: 57320.5,
|
||||
description: '提现到账',
|
||||
createTime: '2026-01-08 15:00:00'
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
flowNo: 'FL202601070001',
|
||||
type: 'income',
|
||||
amount: 2360.0,
|
||||
balance: 62320.5,
|
||||
description: '号卡分配佣金',
|
||||
createTime: '2026-01-07 14:20:00'
|
||||
}
|
||||
])
|
||||
|
||||
const calculatedFee = computed(() => {
|
||||
return withdrawForm.amount * feeRate
|
||||
})
|
||||
|
||||
const actualAmount = computed(() => {
|
||||
return withdrawForm.amount - calculatedFee.value
|
||||
})
|
||||
|
||||
const filteredFlowData = computed(() => {
|
||||
if (flowType.value === 'all') return flowData.value
|
||||
return flowData.value.filter((item) => item.type === flowType.value)
|
||||
})
|
||||
|
||||
const showWithdrawDialog = () => {
|
||||
withdrawForm.amount = 0
|
||||
withdrawForm.bankName = ''
|
||||
withdrawForm.bankAccount = ''
|
||||
withdrawForm.accountName = ''
|
||||
withdrawDialogVisible.value = true
|
||||
}
|
||||
|
||||
const submitWithdraw = async () => {
|
||||
if (!withdrawFormRef.value) return
|
||||
await withdrawFormRef.value.validate((valid) => {
|
||||
if (valid) {
|
||||
ElMessage.success('提现申请提交成功,请等待审核')
|
||||
withdrawDialogVisible.value = false
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const viewWithdrawHistory = () => {
|
||||
ElMessage.info('查看提现记录')
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.page-content {
|
||||
.stat-card {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
|
||||
.stat-icon {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
border-radius: 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: white;
|
||||
font-size: 28px;
|
||||
}
|
||||
|
||||
.stat-content {
|
||||
flex: 1;
|
||||
|
||||
.stat-label {
|
||||
font-size: 14px;
|
||||
color: var(--el-text-color-secondary);
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.stat-value {
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
color: var(--el-text-color-primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
220
src/views/finance/withdrawal-settings/index.vue
Normal file
220
src/views/finance/withdrawal-settings/index.vue
Normal file
@@ -0,0 +1,220 @@
|
||||
<template>
|
||||
<div class="page-content">
|
||||
<ElCard shadow="never">
|
||||
<template #header>
|
||||
<span style="font-weight: 500">提现参数配置</span>
|
||||
</template>
|
||||
|
||||
<ElForm ref="formRef" :model="form" :rules="rules" label-width="150px" style="max-width: 800px">
|
||||
<ElFormItem label="最低提现金额" prop="minAmount">
|
||||
<ElInputNumber v-model="form.minAmount" :min="1" :precision="2" />
|
||||
<span style="margin-left: 8px">元</span>
|
||||
</ElFormItem>
|
||||
|
||||
<ElFormItem label="手续费模式" prop="feeMode">
|
||||
<ElRadioGroup v-model="form.feeMode">
|
||||
<ElRadio value="fixed">固定手续费</ElRadio>
|
||||
<ElRadio value="percent">比例手续费</ElRadio>
|
||||
</ElRadioGroup>
|
||||
</ElFormItem>
|
||||
|
||||
<ElFormItem v-if="form.feeMode === 'fixed'" label="固定手续费" prop="fixedFee">
|
||||
<ElInputNumber v-model="form.fixedFee" :min="0" :precision="2" />
|
||||
<span style="margin-left: 8px">元/笔</span>
|
||||
</ElFormItem>
|
||||
|
||||
<ElFormItem v-if="form.feeMode === 'percent'" label="手续费比例" prop="feePercent">
|
||||
<ElInputNumber v-model="form.feePercent" :min="0" :max="100" :precision="2" />
|
||||
<span style="margin-left: 8px">%</span>
|
||||
</ElFormItem>
|
||||
|
||||
<ElFormItem label="单日提现次数" prop="dailyLimit">
|
||||
<ElInputNumber v-model="form.dailyLimit" :min="1" :max="10" />
|
||||
<span style="margin-left: 8px">次</span>
|
||||
</ElFormItem>
|
||||
|
||||
<ElFormItem label="提现到账时间" prop="arrivalTime">
|
||||
<ElSelect v-model="form.arrivalTime" style="width: 200px">
|
||||
<ElOption label="实时到账" value="realtime" />
|
||||
<ElOption label="2小时内到账" value="2hours" />
|
||||
<ElOption label="24小时内到账" value="24hours" />
|
||||
<ElOption label="T+1到账" value="t1" />
|
||||
<ElOption label="T+3到账" value="t3" />
|
||||
</ElSelect>
|
||||
</ElFormItem>
|
||||
|
||||
<ElFormItem label="工作日提现" prop="workdayOnly">
|
||||
<ElSwitch v-model="form.workdayOnly" />
|
||||
<span style="margin-left: 8px; color: var(--el-text-color-secondary)">
|
||||
{{ form.workdayOnly ? '仅工作日可提现' : '每天都可提现' }}
|
||||
</span>
|
||||
</ElFormItem>
|
||||
|
||||
<ElFormItem label="提现时间段" prop="timeRange">
|
||||
<ElTimePicker
|
||||
v-model="form.timeRange"
|
||||
is-range
|
||||
range-separator="至"
|
||||
start-placeholder="开始时间"
|
||||
end-placeholder="结束时间"
|
||||
format="HH:mm"
|
||||
/>
|
||||
</ElFormItem>
|
||||
|
||||
<ElFormItem label="配置说明" prop="description">
|
||||
<ElInput
|
||||
v-model="form.description"
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
placeholder="请输入配置说明,如配置生效时间等"
|
||||
/>
|
||||
</ElFormItem>
|
||||
|
||||
<ElFormItem>
|
||||
<ElButton type="primary" @click="handleSave">保存配置</ElButton>
|
||||
<ElButton @click="resetForm">重置</ElButton>
|
||||
</ElFormItem>
|
||||
</ElForm>
|
||||
</ElCard>
|
||||
|
||||
<ElCard shadow="never" style="margin-top: 20px">
|
||||
<template #header>
|
||||
<span style="font-weight: 500">配置历史记录</span>
|
||||
</template>
|
||||
|
||||
<ArtTable :data="historyData" index>
|
||||
<template #default>
|
||||
<ElTableColumn label="配置时间" prop="configTime" width="180" />
|
||||
<ElTableColumn label="最低金额" prop="minAmount">
|
||||
<template #default="scope"> ¥{{ scope.row.minAmount.toFixed(2) }} </template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="手续费" prop="fee">
|
||||
<template #default="scope">
|
||||
{{
|
||||
scope.row.feeMode === 'fixed'
|
||||
? `¥${scope.row.fixedFee.toFixed(2)}/笔`
|
||||
: `${scope.row.feePercent}%`
|
||||
}}
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="单日限制" prop="dailyLimit">
|
||||
<template #default="scope"> {{ scope.row.dailyLimit }}次/天 </template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="到账时间" prop="arrivalTime">
|
||||
<template #default="scope">
|
||||
{{ getArrivalTimeText(scope.row.arrivalTime) }}
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="配置人" prop="operator" />
|
||||
<ElTableColumn label="状态" prop="status">
|
||||
<template #default="scope">
|
||||
<ElTag :type="scope.row.status === 'active' ? 'success' : 'info'">
|
||||
{{ scope.row.status === 'active' ? '当前生效' : '已过期' }}
|
||||
</ElTag>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
</template>
|
||||
</ArtTable>
|
||||
</ElCard>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ElMessage } from 'element-plus'
|
||||
import type { FormInstance, FormRules } from 'element-plus'
|
||||
|
||||
defineOptions({ name: 'WithdrawalSettings' })
|
||||
|
||||
const formRef = ref<FormInstance>()
|
||||
|
||||
const form = reactive({
|
||||
minAmount: 100,
|
||||
feeMode: 'percent',
|
||||
fixedFee: 2,
|
||||
feePercent: 0.2,
|
||||
dailyLimit: 3,
|
||||
arrivalTime: '24hours',
|
||||
workdayOnly: false,
|
||||
timeRange: [new Date(2024, 0, 1, 0, 0), new Date(2024, 0, 1, 23, 59)],
|
||||
description: ''
|
||||
})
|
||||
|
||||
const rules = reactive<FormRules>({
|
||||
minAmount: [{ required: true, message: '请输入最低提现金额', trigger: 'blur' }],
|
||||
feeMode: [{ required: true, message: '请选择手续费模式', trigger: 'change' }],
|
||||
dailyLimit: [{ required: true, message: '请输入单日提现次数', trigger: 'blur' }],
|
||||
arrivalTime: [{ required: true, message: '请选择到账时间', trigger: 'change' }]
|
||||
})
|
||||
|
||||
const historyData = ref([
|
||||
{
|
||||
id: '1',
|
||||
configTime: '2026-01-09 10:00:00',
|
||||
minAmount: 100,
|
||||
feeMode: 'percent',
|
||||
fixedFee: 0,
|
||||
feePercent: 0.2,
|
||||
dailyLimit: 3,
|
||||
arrivalTime: '24hours',
|
||||
operator: 'admin',
|
||||
status: 'active'
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
configTime: '2026-01-01 10:00:00',
|
||||
minAmount: 50,
|
||||
feeMode: 'fixed',
|
||||
fixedFee: 2.0,
|
||||
feePercent: 0,
|
||||
dailyLimit: 5,
|
||||
arrivalTime: 't1',
|
||||
operator: 'admin',
|
||||
status: 'expired'
|
||||
}
|
||||
])
|
||||
|
||||
const getArrivalTimeText = (value: string) => {
|
||||
const map: Record<string, string> = {
|
||||
realtime: '实时到账',
|
||||
'2hours': '2小时内',
|
||||
'24hours': '24小时内',
|
||||
t1: 'T+1',
|
||||
t3: 'T+3'
|
||||
}
|
||||
return map[value] || '未知'
|
||||
}
|
||||
|
||||
const handleSave = async () => {
|
||||
if (!formRef.value) return
|
||||
await formRef.value.validate((valid) => {
|
||||
if (valid) {
|
||||
// 添加到历史记录
|
||||
historyData.value.unshift({
|
||||
id: Date.now().toString(),
|
||||
configTime: new Date().toLocaleString('zh-CN'),
|
||||
...form,
|
||||
operator: 'admin',
|
||||
status: 'active'
|
||||
})
|
||||
// 将之前的配置标记为过期
|
||||
historyData.value.slice(1).forEach((item) => {
|
||||
item.status = 'expired'
|
||||
})
|
||||
ElMessage.success('配置保存成功')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const resetForm = () => {
|
||||
formRef.value?.resetFields()
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.page-content {
|
||||
:deep(.el-card__header) {
|
||||
padding: 16px 20px;
|
||||
border-bottom: 1px solid var(--el-border-color-light);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
351
src/views/finance/withdrawal/index.vue
Normal file
351
src/views/finance/withdrawal/index.vue
Normal file
@@ -0,0 +1,351 @@
|
||||
<template>
|
||||
<div class="page-content">
|
||||
<ElRow>
|
||||
<ElCol :xs="24" :sm="12" :lg="6">
|
||||
<ElInput v-model="searchQuery" placeholder="申请人/手机号" clearable></ElInput>
|
||||
</ElCol>
|
||||
<div style="width: 12px"></div>
|
||||
<ElCol :xs="24" :sm="12" :lg="6">
|
||||
<ElSelect v-model="statusFilter" placeholder="审核状态" clearable style="width: 100%">
|
||||
<ElOption label="待审核" value="pending" />
|
||||
<ElOption label="已通过" value="approved" />
|
||||
<ElOption label="已拒绝" value="rejected" />
|
||||
</ElSelect>
|
||||
</ElCol>
|
||||
<div style="width: 12px"></div>
|
||||
<ElCol :xs="24" :sm="12" :lg="6">
|
||||
<ElDatePicker
|
||||
v-model="dateRange"
|
||||
type="daterange"
|
||||
range-separator="至"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</ElCol>
|
||||
<div style="width: 12px"></div>
|
||||
<ElCol :xs="24" :sm="12" :lg="6" class="el-col2">
|
||||
<ElButton v-ripple @click="handleSearch">搜索</ElButton>
|
||||
<ElButton v-ripple @click="handleBatchApprove" :disabled="selectedIds.length === 0"
|
||||
>批量审核</ElButton
|
||||
>
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
|
||||
<ArtTable :data="filteredData" index @selection-change="handleSelectionChange">
|
||||
<template #default>
|
||||
<ElTableColumn type="selection" width="55" />
|
||||
<ElTableColumn label="申请单号" prop="orderNo" min-width="180" />
|
||||
<ElTableColumn label="申请人" prop="applicantName" />
|
||||
<ElTableColumn label="客户类型" prop="customerType">
|
||||
<template #default="scope">
|
||||
<ElTag :type="scope.row.customerType === 'agent' ? '' : 'success'">
|
||||
{{ scope.row.customerType === 'agent' ? '代理商' : '企业客户' }}
|
||||
</ElTag>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="提现金额" prop="amount">
|
||||
<template #default="scope">
|
||||
<span style="color: var(--el-color-danger); font-weight: 500">
|
||||
¥{{ scope.row.amount.toFixed(2) }}
|
||||
</span>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="手续费" prop="fee">
|
||||
<template #default="scope"> ¥{{ scope.row.fee.toFixed(2) }} </template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="实际到账" prop="actualAmount">
|
||||
<template #default="scope">
|
||||
<span style="color: var(--el-color-success); font-weight: 500">
|
||||
¥{{ scope.row.actualAmount.toFixed(2) }}
|
||||
</span>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="收款账户" prop="bankAccount" show-overflow-tooltip />
|
||||
<ElTableColumn label="状态" prop="status">
|
||||
<template #default="scope">
|
||||
<ElTag :type="getStatusTagType(scope.row.status)">
|
||||
{{ getStatusText(scope.row.status) }}
|
||||
</ElTag>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="申请时间" prop="createTime" width="180" />
|
||||
<ElTableColumn fixed="right" label="操作" width="180">
|
||||
<template #default="scope">
|
||||
<el-button link @click="viewDetail(scope.row)">详情</el-button>
|
||||
<el-button
|
||||
v-if="scope.row.status === 'pending'"
|
||||
link
|
||||
type="success"
|
||||
@click="handleApprove(scope.row)"
|
||||
>通过</el-button
|
||||
>
|
||||
<el-button
|
||||
v-if="scope.row.status === 'pending'"
|
||||
link
|
||||
type="danger"
|
||||
@click="handleReject(scope.row)"
|
||||
>拒绝</el-button
|
||||
>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
</template>
|
||||
</ArtTable>
|
||||
|
||||
<!-- 详情对话框 -->
|
||||
<ElDialog v-model="detailDialogVisible" title="提现申请详情" width="700px" align-center>
|
||||
<ElDescriptions :column="2" border>
|
||||
<ElDescriptionsItem label="申请单号">{{ currentItem?.orderNo }}</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="申请人">{{ currentItem?.applicantName }}</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="手机号">{{ currentItem?.phone }}</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="客户类型">
|
||||
{{ currentItem?.customerType === 'agent' ? '代理商' : '企业客户' }}
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="提现金额">
|
||||
<span style="color: var(--el-color-danger); font-weight: 500">
|
||||
¥{{ currentItem?.amount.toFixed(2) }}
|
||||
</span>
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="手续费">¥{{ currentItem?.fee.toFixed(2) }}</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="实际到账">
|
||||
<span style="color: var(--el-color-success); font-weight: 500">
|
||||
¥{{ currentItem?.actualAmount.toFixed(2) }}
|
||||
</span>
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="收款银行">{{ currentItem?.bankName }}</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="收款账户" :span="2">{{
|
||||
currentItem?.bankAccount
|
||||
}}</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="开户姓名">{{ currentItem?.accountName }}</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="申请时间">{{ currentItem?.createTime }}</ElDescriptionsItem>
|
||||
<ElDescriptionsItem label="审核状态">
|
||||
<ElTag :type="getStatusTagType(currentItem?.status || 'pending')">
|
||||
{{ getStatusText(currentItem?.status || 'pending') }}
|
||||
</ElTag>
|
||||
</ElDescriptionsItem>
|
||||
<ElDescriptionsItem v-if="currentItem?.status !== 'pending'" label="审核时间">{{
|
||||
currentItem?.auditTime
|
||||
}}</ElDescriptionsItem>
|
||||
<ElDescriptionsItem v-if="currentItem?.rejectReason" label="拒绝原因" :span="2">{{
|
||||
currentItem?.rejectReason
|
||||
}}</ElDescriptionsItem>
|
||||
</ElDescriptions>
|
||||
</ElDialog>
|
||||
|
||||
<!-- 拒绝对话框 -->
|
||||
<ElDialog v-model="rejectDialogVisible" title="拒绝提现" width="500px" align-center>
|
||||
<ElForm ref="rejectFormRef" :model="rejectForm" :rules="rejectRules" label-width="100px">
|
||||
<ElFormItem label="拒绝原因" prop="reason">
|
||||
<ElInput
|
||||
v-model="rejectForm.reason"
|
||||
type="textarea"
|
||||
:rows="4"
|
||||
placeholder="请输入拒绝原因"
|
||||
/>
|
||||
</ElFormItem>
|
||||
</ElForm>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<ElButton @click="rejectDialogVisible = false">取消</ElButton>
|
||||
<ElButton type="primary" @click="confirmReject">确认拒绝</ElButton>
|
||||
</div>
|
||||
</template>
|
||||
</ElDialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import type { FormInstance, FormRules } from 'element-plus'
|
||||
|
||||
defineOptions({ name: 'WithdrawalManagement' })
|
||||
|
||||
interface WithdrawalItem {
|
||||
id: string
|
||||
orderNo: string
|
||||
applicantName: string
|
||||
phone: string
|
||||
customerType: 'agent' | 'enterprise'
|
||||
amount: number
|
||||
fee: number
|
||||
actualAmount: number
|
||||
bankName: string
|
||||
bankAccount: string
|
||||
accountName: string
|
||||
status: 'pending' | 'approved' | 'rejected'
|
||||
createTime: string
|
||||
auditTime?: string
|
||||
rejectReason?: string
|
||||
}
|
||||
|
||||
const mockData = ref<WithdrawalItem[]>([
|
||||
{
|
||||
id: '1',
|
||||
orderNo: 'WD202601090001',
|
||||
applicantName: '张三',
|
||||
phone: '13800138001',
|
||||
customerType: 'agent',
|
||||
amount: 5000.0,
|
||||
fee: 10.0,
|
||||
actualAmount: 4990.0,
|
||||
bankName: '中国工商银行',
|
||||
bankAccount: '6222 **** **** 1234',
|
||||
accountName: '张三',
|
||||
status: 'pending',
|
||||
createTime: '2026-01-09 10:00:00'
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
orderNo: 'WD202601090002',
|
||||
applicantName: '李四',
|
||||
phone: '13800138002',
|
||||
customerType: 'enterprise',
|
||||
amount: 3000.0,
|
||||
fee: 6.0,
|
||||
actualAmount: 2994.0,
|
||||
bankName: '中国建设银行',
|
||||
bankAccount: '6227 **** **** 5678',
|
||||
accountName: '李四',
|
||||
status: 'approved',
|
||||
createTime: '2026-01-08 14:30:00',
|
||||
auditTime: '2026-01-08 15:00:00'
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
orderNo: 'WD202601090003',
|
||||
applicantName: '王五',
|
||||
phone: '13800138003',
|
||||
customerType: 'agent',
|
||||
amount: 2000.0,
|
||||
fee: 4.0,
|
||||
actualAmount: 1996.0,
|
||||
bankName: '中国农业银行',
|
||||
bankAccount: '6228 **** **** 9012',
|
||||
accountName: '王五',
|
||||
status: 'rejected',
|
||||
createTime: '2026-01-07 16:20:00',
|
||||
auditTime: '2026-01-07 17:00:00',
|
||||
rejectReason: '账户信息与实名不符'
|
||||
}
|
||||
])
|
||||
|
||||
const searchQuery = ref('')
|
||||
const statusFilter = ref('')
|
||||
const dateRange = ref<[Date, Date] | null>(null)
|
||||
const selectedIds = ref<string[]>([])
|
||||
const detailDialogVisible = ref(false)
|
||||
const rejectDialogVisible = ref(false)
|
||||
const currentItem = ref<WithdrawalItem | null>(null)
|
||||
const rejectFormRef = ref<FormInstance>()
|
||||
|
||||
const rejectForm = reactive({
|
||||
reason: ''
|
||||
})
|
||||
|
||||
const rejectRules = reactive<FormRules>({
|
||||
reason: [{ required: true, message: '请输入拒绝原因', trigger: 'blur' }]
|
||||
})
|
||||
|
||||
const filteredData = computed(() => {
|
||||
let data = mockData.value
|
||||
if (searchQuery.value) {
|
||||
data = data.filter(
|
||||
(item) => item.applicantName.includes(searchQuery.value) || item.phone.includes(searchQuery.value)
|
||||
)
|
||||
}
|
||||
if (statusFilter.value) {
|
||||
data = data.filter((item) => item.status === statusFilter.value)
|
||||
}
|
||||
return data
|
||||
})
|
||||
|
||||
const getStatusText = (status: string) => {
|
||||
const map: Record<string, string> = {
|
||||
pending: '待审核',
|
||||
approved: '已通过',
|
||||
rejected: '已拒绝'
|
||||
}
|
||||
return map[status] || '未知'
|
||||
}
|
||||
|
||||
const getStatusTagType = (status: string) => {
|
||||
const map: Record<string, string> = {
|
||||
pending: 'warning',
|
||||
approved: 'success',
|
||||
rejected: 'danger'
|
||||
}
|
||||
return map[status] || 'info'
|
||||
}
|
||||
|
||||
const handleSearch = () => {}
|
||||
|
||||
const handleSelectionChange = (selection: WithdrawalItem[]) => {
|
||||
selectedIds.value = selection.map((item) => item.id)
|
||||
}
|
||||
|
||||
const viewDetail = (row: WithdrawalItem) => {
|
||||
currentItem.value = row
|
||||
detailDialogVisible.value = true
|
||||
}
|
||||
|
||||
const handleApprove = (row: WithdrawalItem) => {
|
||||
ElMessageBox.confirm(
|
||||
`确认通过提现申请?金额:¥${row.amount.toFixed(2)},实际到账:¥${row.actualAmount.toFixed(2)}`,
|
||||
'审核确认',
|
||||
{
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'success'
|
||||
}
|
||||
).then(() => {
|
||||
row.status = 'approved'
|
||||
row.auditTime = new Date().toLocaleString('zh-CN')
|
||||
ElMessage.success('审核通过')
|
||||
})
|
||||
}
|
||||
|
||||
const handleReject = (row: WithdrawalItem) => {
|
||||
currentItem.value = row
|
||||
rejectForm.reason = ''
|
||||
rejectDialogVisible.value = true
|
||||
}
|
||||
|
||||
const confirmReject = async () => {
|
||||
if (!rejectFormRef.value) return
|
||||
await rejectFormRef.value.validate((valid) => {
|
||||
if (valid && currentItem.value) {
|
||||
currentItem.value.status = 'rejected'
|
||||
currentItem.value.auditTime = new Date().toLocaleString('zh-CN')
|
||||
currentItem.value.rejectReason = rejectForm.reason
|
||||
rejectDialogVisible.value = false
|
||||
ElMessage.success('已拒绝提现申请')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const handleBatchApprove = () => {
|
||||
ElMessageBox.confirm(`确认批量审核 ${selectedIds.value.length} 条提现申请吗?`, '批量审核', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
selectedIds.value.forEach((id) => {
|
||||
const item = mockData.value.find((i) => i.id === id)
|
||||
if (item && item.status === 'pending') {
|
||||
item.status = 'approved'
|
||||
item.auditTime = new Date().toLocaleString('zh-CN')
|
||||
}
|
||||
})
|
||||
ElMessage.success('批量审核成功')
|
||||
selectedIds.value = []
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.page-content {
|
||||
:deep(.el-descriptions__label) {
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user