钱包管理模块
This commit is contained in:
parent
a3ef32d035
commit
6b49a037e0
|
|
@ -0,0 +1,36 @@
|
|||
import { request } from '@/api'
|
||||
|
||||
// 提现订单列表
|
||||
export const getWithdrawOrderList = (params: {
|
||||
page: number
|
||||
page_size: number
|
||||
start_time?: string
|
||||
end_time?: string
|
||||
status?: string
|
||||
}) => {
|
||||
return request.get('/upay/withdrawOrderList', params as any)
|
||||
}
|
||||
|
||||
// 刷新地址余额
|
||||
export const balanceRefresh = (params: { address?: string, addressType?: string }) => {
|
||||
return request.post('/upay/balanceRefresh', params)
|
||||
}
|
||||
|
||||
// 提现地址列表
|
||||
export const getAddressList = (params: {
|
||||
page: number
|
||||
page_size: number
|
||||
address?: string
|
||||
addressType?: string
|
||||
}) => {
|
||||
return request.post('/upay/addressList', params as any)
|
||||
}
|
||||
|
||||
// 提现
|
||||
export const withdrawAction = (params: {
|
||||
from: string
|
||||
to: string
|
||||
amount: string
|
||||
}) => {
|
||||
return request.post('/upay/withdrawAction', params)
|
||||
}
|
||||
|
|
@ -0,0 +1,228 @@
|
|||
<template>
|
||||
<div class="address-list-page table_form-container">
|
||||
<!-- 搜索 -->
|
||||
<Search
|
||||
:search-form="searchForm"
|
||||
:search-options="searchOptions"
|
||||
:button-loading="loading"
|
||||
@search="handleSearch"
|
||||
@reset="handleReset"
|
||||
>
|
||||
</Search>
|
||||
|
||||
<!-- 表格 -->
|
||||
<Table
|
||||
ref="tableRef"
|
||||
:table-data="tableData"
|
||||
:columns="tableColumnsOptions"
|
||||
row-key="address"
|
||||
:loading="loading"
|
||||
@rowClick="handleRowClick"
|
||||
>
|
||||
<template #action="{ row }">
|
||||
<el-button type="primary" size="small" @click.stop="openWithdrawDialog(row)">提现</el-button>
|
||||
<el-button size="small" @click.stop="handleRefresh(row)">刷新</el-button>
|
||||
</template>
|
||||
</Table>
|
||||
|
||||
<!-- 分页 -->
|
||||
<Pagination
|
||||
v-model="queryParams.page"
|
||||
v-model:pageSizeValue="queryParams.page_size"
|
||||
:total="total"
|
||||
:layout="'prev, pager, next'"
|
||||
@pagination-change="getList"
|
||||
/>
|
||||
|
||||
<!-- 提现弹窗 -->
|
||||
<el-dialog v-model="withdrawDialogVisible" title="提现" width="600px">
|
||||
<el-form :model="withdrawForm" label-width="80px">
|
||||
<el-form-item label="来源地址">
|
||||
<el-input v-model="withdrawForm.from" disabled />
|
||||
</el-form-item>
|
||||
<el-form-item label="目标地址" required>
|
||||
<el-input v-model="withdrawForm.to" placeholder="请输入目标地址" />
|
||||
</el-form-item>
|
||||
<el-form-item label="金额" required>
|
||||
<el-input v-model="withdrawForm.amount" placeholder="请输入金额" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="withdrawDialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" :loading="withdrawLoading" @click="handleWithdraw">确认</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, onMounted } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import Search from '@/components/common/Search.vue'
|
||||
import Table from '@/components/common/Table.vue'
|
||||
import Pagination from '@/components/common/Pagination.vue'
|
||||
import { usePageLoading } from '@/composables/useLoading'
|
||||
import { tableColumns, searchOptions } from './options'
|
||||
import { getAddressList, balanceRefresh, withdrawAction } from '@/api/modules/wallet/wallet'
|
||||
|
||||
defineOptions({
|
||||
name: 'AddressList'
|
||||
})
|
||||
|
||||
interface AddressRow {
|
||||
address: string
|
||||
trxBalance: string
|
||||
usdtBalance: string
|
||||
addressType: string
|
||||
createdAt: string
|
||||
}
|
||||
|
||||
const tableRef = ref()
|
||||
const tableData = ref<AddressRow[]>([])
|
||||
const selectedRow = ref<AddressRow | null>(null)
|
||||
const { loading, startLoading, stopLoading } = usePageLoading()
|
||||
|
||||
// 提现弹窗
|
||||
const withdrawDialogVisible = ref(false)
|
||||
const withdrawLoading = ref(false)
|
||||
const withdrawForm = reactive({
|
||||
from: '',
|
||||
to: '',
|
||||
amount: '',
|
||||
})
|
||||
|
||||
// 分页参数
|
||||
const queryParams = reactive({
|
||||
page: 1,
|
||||
page_size: 20,
|
||||
})
|
||||
const total = ref(0)
|
||||
|
||||
// 搜索表单
|
||||
const searchForm = ref({
|
||||
addressType: '',
|
||||
address: '',
|
||||
})
|
||||
|
||||
// 表格列配置
|
||||
const tableColumnsOptions = tableColumns
|
||||
|
||||
// 获取列表数据
|
||||
const getList = async () => {
|
||||
startLoading()
|
||||
try {
|
||||
const res = await getAddressList({
|
||||
address: searchForm.value.address || '',
|
||||
addressType: searchForm.value.addressType || '',
|
||||
page: queryParams.page,
|
||||
page_size: queryParams.page_size,
|
||||
})
|
||||
|
||||
if (res) {
|
||||
tableData.value = res?.address_list?.data?.list || []
|
||||
if (res?.address_list?.data?.list?.length === 20) {
|
||||
total.value = queryParams.page * queryParams.page_size
|
||||
}else{
|
||||
total.value = queryParams.page * queryParams.page_size - 1
|
||||
}
|
||||
console.log("total.value", total.value)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取列表失败', error)
|
||||
} finally {
|
||||
stopLoading()
|
||||
}
|
||||
}
|
||||
|
||||
// 搜索
|
||||
const handleSearch = () => {
|
||||
queryParams.page = 1
|
||||
getList()
|
||||
}
|
||||
|
||||
// 重置
|
||||
const handleReset = () => {
|
||||
searchForm.value = {
|
||||
addressType: '',
|
||||
address: '',
|
||||
}
|
||||
queryParams.page = 1
|
||||
getList()
|
||||
}
|
||||
|
||||
// 行点击
|
||||
const handleRowClick = (row: AddressRow) => {
|
||||
selectedRow.value = row
|
||||
}
|
||||
|
||||
// 打开提现弹窗
|
||||
const openWithdrawDialog = (row?: AddressRow) => {
|
||||
const targetRow = row || selectedRow.value
|
||||
if (!targetRow) {
|
||||
ElMessage.warning('请选择一条记录')
|
||||
return
|
||||
}
|
||||
withdrawForm.from = targetRow.address
|
||||
withdrawForm.to = ''
|
||||
withdrawForm.amount = ''
|
||||
withdrawDialogVisible.value = true
|
||||
}
|
||||
|
||||
// 提现
|
||||
const handleWithdraw = async () => {
|
||||
if (!withdrawForm.to) {
|
||||
ElMessage.warning('请输入目标地址')
|
||||
return
|
||||
}
|
||||
if (!withdrawForm.amount) {
|
||||
ElMessage.warning('请输入金额')
|
||||
return
|
||||
}
|
||||
withdrawLoading.value = true
|
||||
try {
|
||||
await withdrawAction({
|
||||
from: withdrawForm.from,
|
||||
to: withdrawForm.to,
|
||||
amount: withdrawForm.amount,
|
||||
})
|
||||
ElMessage.success('提现成功')
|
||||
withdrawDialogVisible.value = false
|
||||
getList()
|
||||
} catch (error) {
|
||||
console.error('提现失败', error)
|
||||
} finally {
|
||||
withdrawLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 刷新
|
||||
const handleRefresh = async (row?: AddressRow) => {
|
||||
const targetRow = row || selectedRow.value
|
||||
if (!targetRow) {
|
||||
ElMessage.warning('请选择一条记录')
|
||||
return
|
||||
}
|
||||
try {
|
||||
const res = await balanceRefresh({ address: targetRow.address, addressType: targetRow.addressType })
|
||||
console.log(res)
|
||||
if (res) {
|
||||
ElMessage.success('刷新成功')
|
||||
const index = tableData.value.findIndex(item => item.address === targetRow.address)
|
||||
if (index !== -1) {
|
||||
tableData.value[index]!.trxBalance = res.data;
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('刷新失败', error)
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
getList()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.address-list-page {
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
// 提现地址列表页面表格列配置
|
||||
export const tableColumns = [
|
||||
// 序号
|
||||
{ label: '序号', type: 'index', width: 60, align: 'center' as const },
|
||||
// 地址
|
||||
{ label: '地址', prop: 'address', width: 400, align: 'center' as const, copy: true },
|
||||
// TRX余额
|
||||
{ label: 'TRX余额', prop: 'trxBalance', align: 'center' as const },
|
||||
// USDT余额
|
||||
{ label: 'USDT余额', prop: 'usdtBalance', align: 'center' as const },
|
||||
// 地址类型
|
||||
{ label: '地址类型', prop: 'addressType', align: 'center' as const },
|
||||
// 创建时间
|
||||
{ label: '创建时间', prop: 'createdAt', align: 'center' as const },
|
||||
// 操作
|
||||
{ label: '操作', prop: 'action', width: 160, slotName: 'action' as const },
|
||||
]
|
||||
|
||||
// 搜索配置
|
||||
export const searchOptions = [
|
||||
{
|
||||
prop: 'addressType',
|
||||
label: '钱包类型',
|
||||
type: 'select' as const,
|
||||
placeholder: '请选择钱包类型',
|
||||
width: '220px',
|
||||
options: [
|
||||
{ label: 'TRX', value: 'TRX' },
|
||||
{ label: 'ETH', value: 'ETH' },
|
||||
{ label: 'BTC', value: 'BTC' },
|
||||
],
|
||||
},
|
||||
{
|
||||
prop: 'address',
|
||||
label: '钱包地址',
|
||||
type: 'input' as const,
|
||||
placeholder: '请输入钱包地址',
|
||||
width: '220px',
|
||||
},
|
||||
]
|
||||
|
|
@ -0,0 +1,144 @@
|
|||
<template>
|
||||
<div class="withdraw-order-list-page table_form-container">
|
||||
<!-- 搜索 -->
|
||||
<Search :search-form="searchForm" :search-options="searchOptions" :button-loading="loading"
|
||||
@search="handleSearch" @reset="handleReset" />
|
||||
|
||||
<!-- 表格 -->
|
||||
<Table ref="tableRef" :table-data="tableData" :columns="tableColumnsOptions" row-key="id" :loading="loading"
|
||||
@rowClick="handleRowClick" />
|
||||
|
||||
<!-- 分页 -->
|
||||
<Pagination v-model="queryParams.page" v-model:pageSizeValue="queryParams.page_size" :total="total"
|
||||
:layout="'prev, pager, next'" @pagination-change="getList" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, onMounted } from 'vue'
|
||||
import Search from '@/components/common/Search.vue'
|
||||
import Table from '@/components/common/Table.vue'
|
||||
import Pagination from '@/components/common/Pagination.vue'
|
||||
import { usePageLoading } from '@/composables/useLoading'
|
||||
import { tableColumns, searchOptions } from './options'
|
||||
import { getLast7DaysRange } from '@/utils/timeUtils'
|
||||
import { getWithdrawOrderList } from '@/api/modules/wallet/wallet'
|
||||
|
||||
defineOptions({
|
||||
name: 'WithdrawOrderList'
|
||||
})
|
||||
|
||||
interface WithdrawOrderRow {
|
||||
id: number
|
||||
user_id: number
|
||||
order_n: string
|
||||
notify_n: string | null
|
||||
from: string
|
||||
to: string
|
||||
amount: string
|
||||
addressType: string | null
|
||||
balance: string | null
|
||||
status: number
|
||||
create_time: number
|
||||
success_time: number | null
|
||||
tx_id: string | null
|
||||
created_at: string
|
||||
updated_at: string
|
||||
}
|
||||
|
||||
const tableRef = ref()
|
||||
const tableData = ref<WithdrawOrderRow[]>([])
|
||||
const { loading, startLoading, stopLoading } = usePageLoading()
|
||||
|
||||
// 分页参数
|
||||
const queryParams = reactive({
|
||||
page: 1,
|
||||
page_size: 20,
|
||||
})
|
||||
const total = ref(0)
|
||||
|
||||
// 获取近七天时间范围(格式化字符串)
|
||||
const getDefaultTimeRange = () => {
|
||||
const range = getLast7DaysRange()
|
||||
const formatDate = (d: Date): string => {
|
||||
const year = d.getFullYear()
|
||||
const month = String(d.getMonth() + 1).padStart(2, '0')
|
||||
const day = String(d.getDate()).padStart(2, '0')
|
||||
const hours = String(d.getHours()).padStart(2, '0')
|
||||
const minutes = String(d.getMinutes()).padStart(2, '0')
|
||||
const seconds = String(d.getSeconds()).padStart(2, '0')
|
||||
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`
|
||||
}
|
||||
return {
|
||||
start_time: formatDate(range.startTime),
|
||||
end_time: formatDate(range.endTime),
|
||||
}
|
||||
}
|
||||
|
||||
// 搜索表单
|
||||
const searchForm = ref({
|
||||
status: '',
|
||||
start_time: '',
|
||||
end_time: '',
|
||||
})
|
||||
|
||||
// 表格列配置
|
||||
const tableColumnsOptions = tableColumns
|
||||
|
||||
// 获取列表数据
|
||||
const getList = async () => {
|
||||
startLoading()
|
||||
try {
|
||||
const res = await getWithdrawOrderList({
|
||||
status: searchForm.value.status || '',
|
||||
start_time: searchForm.value.start_time || '',
|
||||
end_time: searchForm.value.end_time || '',
|
||||
page: queryParams.page || 1,
|
||||
page_size: queryParams.page_size || 20,
|
||||
})
|
||||
if (res) {
|
||||
tableData.value = res?.data || []
|
||||
total.value = res?.total || 0
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取列表失败', error)
|
||||
} finally {
|
||||
stopLoading()
|
||||
}
|
||||
}
|
||||
|
||||
// 搜索
|
||||
const handleSearch = () => {
|
||||
queryParams.page = 1
|
||||
getList()
|
||||
}
|
||||
|
||||
// 重置
|
||||
const handleReset = () => {
|
||||
const range = getDefaultTimeRange()
|
||||
searchForm.value = {
|
||||
status: '',
|
||||
start_time: range.start_time,
|
||||
end_time: range.end_time,
|
||||
}
|
||||
queryParams.page = 1
|
||||
getList()
|
||||
}
|
||||
|
||||
// 行点击
|
||||
const handleRowClick = (row: WithdrawOrderRow) => {
|
||||
console.log('选中行', row)
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
// 初始化默认时间范围
|
||||
const range = getDefaultTimeRange()
|
||||
searchForm.value.start_time = range.start_time
|
||||
searchForm.value.end_time = range.end_time
|
||||
getList()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.withdraw-order-list-page {}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
// 状态选项
|
||||
const statusOptions = [
|
||||
{ label: '未完成', value: 1 },
|
||||
{ label: '成功', value: 2 },
|
||||
{ label: '失败', value: 3 },
|
||||
]
|
||||
|
||||
// 提现订单列表页面表格列配置
|
||||
export const tableColumns = [
|
||||
// 序号
|
||||
{ label: '序号', type: 'index', width: 60, align: 'center' as const },
|
||||
// 用户ID
|
||||
// { label: '用户ID', prop: 'user_id' },
|
||||
// 订单号
|
||||
{ label: '订单号', prop: 'order_n', width: 300, align: 'center' as const, copy: true },
|
||||
// 通知号
|
||||
{ label: '通知号', prop: 'notify_n', width: 200, align: 'center' as const },
|
||||
// 来源地址
|
||||
{ label: '来源地址', prop: 'from', width: 400, align: 'center' as const, copy: true },
|
||||
// 目标地址
|
||||
{ label: '目标地址', prop: 'to', width: 400, align: 'center' as const, copy: true },
|
||||
// 金额
|
||||
{ label: '金额', prop: 'amount', width: 160, align: 'center' as const },
|
||||
// 地址类型
|
||||
{ label: '地址类型', prop: 'addressType', width: 100, align: 'center' as const },
|
||||
// 余额
|
||||
{ label: '余额', prop: 'balance', width: 160, align: 'center' as const },
|
||||
// 状态
|
||||
{ label: '状态', prop: 'status', width: 100, align: 'center' as const, options: statusOptions },
|
||||
// 创建时间
|
||||
{ label: '创建时间', prop: 'create_time', width: 200, align: 'center' as const },
|
||||
// 成功时间
|
||||
{ label: '成功时间', prop: 'success_time', width: 200, align: 'center' as const },
|
||||
// 交易ID
|
||||
{ label: '交易ID', prop: 'tx_id', width: 400, align: 'center' as const },
|
||||
]
|
||||
|
||||
// 搜索配置
|
||||
export const searchOptions = [
|
||||
{
|
||||
prop: 'status',
|
||||
label: '状态',
|
||||
type: 'select' as const,
|
||||
placeholder: '请选择状态',
|
||||
width: '160px',
|
||||
options: statusOptions,
|
||||
},
|
||||
{
|
||||
prop: 'start_time',
|
||||
label: '开始时间',
|
||||
type: 'date' as const,
|
||||
dateType: 'datetime' as const,
|
||||
placeholder: '开始时间',
|
||||
valueFormat: 'YYYY-MM-DD HH:mm:ss',
|
||||
format: 'YYYY-MM-DD',
|
||||
width: '220px',
|
||||
defaultTime: 'start' as const,
|
||||
},
|
||||
{
|
||||
prop: 'end_time',
|
||||
label: '结束时间',
|
||||
type: 'date' as const,
|
||||
dateType: 'datetime' as const,
|
||||
placeholder: '结束时间',
|
||||
valueFormat: 'YYYY-MM-DD HH:mm:ss',
|
||||
format: 'YYYY-MM-DD',
|
||||
width: '220px',
|
||||
defaultTime: 'end' as const,
|
||||
},
|
||||
]
|
||||
Loading…
Reference in New Issue