代码修改
This commit is contained in:
parent
115103fa9a
commit
f5826a889f
@ -59,3 +59,6 @@ export const getExchangeList = (params:any) => request.get('/v1/balance/exchange
|
||||
|
||||
// 兑换算力点
|
||||
export const exchangePoint = (params:any) => request.put('/v1/balance/exchange_point',params)
|
||||
|
||||
// 提现
|
||||
export const getWithdraw = (params:any) => request.put('/v1/balance/withdraw',params)
|
||||
|
||||
@ -42,6 +42,7 @@ request.interceptors.response.use(
|
||||
if (code === 1) {
|
||||
return data??code;
|
||||
} else {
|
||||
console.log("Response Data:", response);
|
||||
// 可抛出业务错误
|
||||
return Promise.reject(new Error(message || "请求失败"));
|
||||
}
|
||||
@ -56,6 +57,9 @@ request.interceptors.response.use(
|
||||
setTimeout(() => {
|
||||
window.location.href = "/login";
|
||||
}, 3000);
|
||||
} else if(res.status === 400){
|
||||
message.error(res.data);
|
||||
return
|
||||
} else {
|
||||
return Promise.reject(error.response.data);
|
||||
}
|
||||
|
||||
@ -22,7 +22,10 @@
|
||||
<div v-if="userInfo.certificationStatus !== 'CERTIFICATION_PASSED'">
|
||||
<span style="margin-right: 25px;">认证类型</span><span style="color: red;">未实名认证</span>
|
||||
</div>
|
||||
<div style="color:#1677ff;" v-if="userInfo.certificationStatus !== 'CERTIFICATION_PASSED'">前往认证
|
||||
<div
|
||||
@click="goCertification"
|
||||
style="color:#1677ff;"
|
||||
v-if="userInfo.certificationStatus !== 'CERTIFICATION_PASSED'" >前往认证
|
||||
</div>
|
||||
<div v-if="userInfo.certificationStatus == 'CERTIFICATION_PASSED'">
|
||||
<span style="margin-right: 25px;">认证类型</span><span>{{ certificationInfo.certificationType
|
||||
@ -773,6 +776,14 @@ const getCertificationInfo = async () => {
|
||||
message.error('获取认证信息失败');
|
||||
}
|
||||
};
|
||||
|
||||
// 前往认证
|
||||
const goCertification = () => {
|
||||
router.push('/layout/admin/realnameAuth');
|
||||
};
|
||||
|
||||
|
||||
// 前往修改手机号
|
||||
onBeforeMount(() => {
|
||||
const userInfoStr = localStorage.getItem('userInfo');
|
||||
if (userInfoStr) {
|
||||
|
||||
@ -108,19 +108,19 @@
|
||||
<a-table :columns="columns" :data-source="rechargeRecords" :pagination="pagination" :loading="tableLoading"
|
||||
@change="handleTableChange" size="middle" bordered>
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.key === 'amount'">
|
||||
<span class="amount-cell">¥{{ record.amount }}</span>
|
||||
<template v-if="column.key === 'topUpAmount'">
|
||||
<span class="amount-cell">¥{{ record.topUpAmount }}</span>
|
||||
</template>
|
||||
<template v-else-if="column.key === 'rechargeTime'">
|
||||
{{ formatDateTime(record.rechargeTime) }}
|
||||
<template v-else-if="column.key === 'created_at'">
|
||||
{{ formatDateTime(record.created_at) }}
|
||||
</template>
|
||||
<template v-else-if="column.key === 'paymentMethod'">
|
||||
<a-tag :color="getPaymentMethodColor(record.paymentMethod)">
|
||||
{{ getPaymentMethodLabel(record.paymentMethod) }}
|
||||
<template v-else-if="column.key === 'payMethod'">
|
||||
<a-tag :color="getPaymentMethodColor(record.payMethod)">
|
||||
{{ getPaymentMethodLabel(record.payMethod) }}
|
||||
</a-tag>
|
||||
</template>
|
||||
<template v-else-if="column.key === 'accountBalance'">
|
||||
¥{{ formatCurrency(record.accountBalance) }}
|
||||
<template v-else-if="column.key === 'balance'">
|
||||
¥{{ formatCurrency(record.balance) }}
|
||||
</template>
|
||||
<template v-else-if="column.key === 'status'">
|
||||
<a-tag :color="getStatusColor(record.status)">
|
||||
@ -202,9 +202,9 @@ const customAmountError = ref('')
|
||||
|
||||
// 充值方式
|
||||
const paymentMethods = ref([
|
||||
{ value: 'alipay', name: '支付宝支付', icon: AlipayOutlined, color: '#1677ff' },
|
||||
{ value: 'wechat', name: '微信支付', icon: WechatOutlined, color: '#07c160' },
|
||||
{ value: 'bank', name: '对公付款', icon: BankOutlined, color: '#722ed1' }
|
||||
{ value: "1", name: '支付宝支付', icon: AlipayOutlined, color: '#1677ff' },
|
||||
{ value: "2", name: '微信支付', icon: WechatOutlined, color: '#07c160' },
|
||||
{ value: "3", name: '银行卡支付', icon: BankOutlined, color: '#722ed1' }
|
||||
])
|
||||
const selectedPaymentMethod = ref('alipay')
|
||||
|
||||
@ -225,12 +225,12 @@ const rechargeRecords = ref([])
|
||||
|
||||
// 表格列
|
||||
const columns = ref([
|
||||
{ title: '充值金额', dataIndex: 'amount', key: 'amount', align: 'right', width: 120 },
|
||||
{ title: '充值时间', dataIndex: 'rechargeTime', key: 'rechargeTime', width: 180, sorter: true },
|
||||
{ title: '支付方式', dataIndex: 'paymentMethod', key: 'paymentMethod', width: 120 },
|
||||
{ title: '账户余额', dataIndex: 'accountBalance', key: 'accountBalance', align: 'right', width: 140 },
|
||||
{ title: '状态', dataIndex: 'status', key: 'status', width: 100 },
|
||||
{ title: '操作', key: 'action', width: 80, align: 'center' }
|
||||
{ title: '充值金额', dataIndex: 'topUpAmount', key: 'topUpAmount', align: 'center', width: 120 },
|
||||
{ title: '充值时间', dataIndex: 'created_at', key: 'created_at', width: 180,align: 'center', sorter: true },
|
||||
{ title: '支付方式', dataIndex: 'payMethod', key: 'payMethod', align: 'center',width: 120 },
|
||||
{ title: '账户余额', dataIndex: 'balance', key: 'balance', align: 'center', width: 140 },
|
||||
// { title: '状态', dataIndex: 'status', key: 'status', width: 100 },
|
||||
// { title: '操作', key: 'action', width: 80, align: 'center' }
|
||||
])
|
||||
|
||||
// 分页
|
||||
@ -299,7 +299,9 @@ const selectPaymentMethod = (method) => {
|
||||
|
||||
// 支付方式标签 & 颜色
|
||||
const getPaymentMethodLabel = (method) => {
|
||||
console.log("===21",method)
|
||||
const payment = paymentMethods.value.find(m => m.value === method)
|
||||
console.log("===2",payment)
|
||||
return payment ? payment.name : method
|
||||
}
|
||||
const getPaymentMethodColor = (method) => {
|
||||
|
||||
@ -2,7 +2,6 @@
|
||||
<div class="withdrawal-management">
|
||||
<!-- 提现账户信息卡片 -->
|
||||
<a-row :gutter="24" class="mb-6">
|
||||
|
||||
<a-col :span="24">
|
||||
<a-card title="可提现金额">
|
||||
<div class="balance-info">
|
||||
@ -24,9 +23,7 @@
|
||||
|
||||
<!-- 提现记录查询 -->
|
||||
<a-card title="提现记录" class="mb-6">
|
||||
<template #extra>
|
||||
|
||||
</template>
|
||||
<template #extra></template>
|
||||
|
||||
<!-- 查询条件 -->
|
||||
<a-form layout="inline" :model="searchParams" class="mb-4">
|
||||
@ -44,26 +41,26 @@
|
||||
|
||||
<!-- 提现记录表格 -->
|
||||
<a-table :columns="columns" :data-source="withdrawalRecords" :pagination="pagination" @change="handleTableChange"
|
||||
:loading="loading" rowKey="id">
|
||||
:loading="loading" rowKey="withdraw_number">
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.key === 'amount'">
|
||||
<span class="amount-cell">{{ formatCurrency(record.amount) }}元</span>
|
||||
<!-- 提现金额 -->
|
||||
<template v-if="column.key === 'withdrawAmount'">
|
||||
<span class="amount-cell">{{ formatCurrency(record.withdrawAmount) }}元</span>
|
||||
</template>
|
||||
|
||||
<template v-else-if="column.key === 'status'">
|
||||
<a-tag :color="getStatusColor(record.status)">
|
||||
{{ getStatusText(record.status) }}
|
||||
<!-- 状态 -->
|
||||
<template v-else-if="column.key === 'withdrawStatus'">
|
||||
<a-tag :color="getStatusColor(record.withdrawStatus)">
|
||||
{{ getStatusText(record.withdrawStatus) }}
|
||||
</a-tag>
|
||||
</template>
|
||||
|
||||
<template v-else-if="column.key === 'createdAt'">
|
||||
{{ formatDate(record.createdAt) }}
|
||||
</template>
|
||||
|
||||
<template v-else-if="column.key === 'completedAt'">
|
||||
{{ record.completedAt ? formatDate(record.completedAt) : '-' }}
|
||||
<!-- 申请时间 -->
|
||||
<template v-else-if="column.key === 'created_at'">
|
||||
{{ formatDate(record.created_at) }}
|
||||
</template>
|
||||
|
||||
<!-- 操作 -->
|
||||
<template v-else-if="column.key === 'actions'">
|
||||
<a-button type="link" @click="viewDetail(record)">查看详情</a-button>
|
||||
</template>
|
||||
@ -87,16 +84,15 @@
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item label="提现到账账户" name="accountId">
|
||||
<a-select v-model:value="withdrawalForm.accountId" placeholder="请选择提现账户">
|
||||
<a-select-option :value="accountInfo.id">
|
||||
{{ accountInfo.bank }} ({{ accountInfo.number }})
|
||||
<a-select v-model:value="withdrawalForm.accountId" placeholder="请选择提现账户" :loading="bankLoading">
|
||||
<a-select-option v-for="bank in bankCards" :key="bank.id" :value="bank.id">
|
||||
{{ getBankCardDisplay(bank) }}
|
||||
</a-select-option>
|
||||
<a-select-option v-if="!bankCards.length && !bankLoading" disabled>
|
||||
暂无银行卡信息,请先添加银行卡
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
|
||||
<a-alert v-if="withdrawalForm.amount"
|
||||
:message="`预计到账金额: ${formatCurrency(calculateActualAmount(withdrawalForm.amount))}元`" type="info" show-icon
|
||||
class="mb-4" />
|
||||
</a-form>
|
||||
</a-modal>
|
||||
</div>
|
||||
@ -107,22 +103,21 @@ import { ref, reactive, onMounted } from 'vue'
|
||||
import { message } from 'ant-design-vue'
|
||||
import dayjs from 'dayjs'
|
||||
import { getWithdrawList } from "@/apis/home"
|
||||
import { getBankCardInfo, getWithdraw } from "@/apis/admin"
|
||||
|
||||
// 账户信息
|
||||
const accountInfo = reactive({
|
||||
id: '1',
|
||||
type: '银行账户',
|
||||
number: '6228 **** **** 5678',
|
||||
name: '张三',
|
||||
bank: '中国工商银行',
|
||||
availableBalance: 5000.00
|
||||
availableBalance: 0
|
||||
})
|
||||
|
||||
// 银行卡信息
|
||||
const bankCards = ref([])
|
||||
const bankLoading = ref(false)
|
||||
|
||||
// 提现记录查询参数
|
||||
const searchParams = reactive({
|
||||
orderNo: '',
|
||||
account: undefined,
|
||||
status: undefined,
|
||||
dateRange: [dayjs().subtract(30, 'day'), dayjs()]
|
||||
dateRange: []
|
||||
})
|
||||
|
||||
// 分页配置
|
||||
@ -135,47 +130,78 @@ const pagination = reactive({
|
||||
showTotal: total => `共 ${total} 条记录`
|
||||
})
|
||||
|
||||
// 表格列定义
|
||||
// 提现状态枚举映射
|
||||
const WITHDRAW_STATUS_MAP = {
|
||||
'PendingReview': {
|
||||
text: '待审核',
|
||||
color: 'orange'
|
||||
},
|
||||
'PendingWithdraw': {
|
||||
text: '待提现',
|
||||
color: 'blue'
|
||||
},
|
||||
'WithdrawalSuccessful': {
|
||||
text: '提现成功',
|
||||
color: 'green'
|
||||
},
|
||||
'WithdrawalFailed': {
|
||||
text: '提现失败',
|
||||
color: 'red'
|
||||
},
|
||||
'RefuseWithdraw': {
|
||||
text: '拒绝提现',
|
||||
color: 'red'
|
||||
}
|
||||
}
|
||||
|
||||
// 获取状态文本
|
||||
const getStatusText = (status) => {
|
||||
return WITHDRAW_STATUS_MAP[status]?.text || status
|
||||
}
|
||||
|
||||
// 获取状态颜色
|
||||
const getStatusColor = (status) => {
|
||||
return WITHDRAW_STATUS_MAP[status]?.color || 'default'
|
||||
}
|
||||
|
||||
// 表格列定义 - 根据接口返回数据调整
|
||||
const columns = [
|
||||
{
|
||||
title: '提现单号',
|
||||
dataIndex: 'orderNo',
|
||||
key: 'orderNo',
|
||||
dataIndex: 'withdraw_number',
|
||||
key: 'withdraw_number',
|
||||
width: 200
|
||||
},
|
||||
{
|
||||
title: '账户',
|
||||
key: 'account',
|
||||
width: 180,
|
||||
render: (_, record) => `${record.bank} (${record.accountNumber})`
|
||||
title: '账户编号',
|
||||
dataIndex: 'bankCardNo',
|
||||
key: 'bankCardNo',
|
||||
width: 200,
|
||||
customRender: ({ text }) => maskCardNumber(text)
|
||||
},
|
||||
{
|
||||
title: '账户名',
|
||||
dataIndex: 'name',
|
||||
key: 'name',
|
||||
width: 180
|
||||
},
|
||||
{
|
||||
title: '提现金额',
|
||||
key: 'amount',
|
||||
dataIndex: 'withdrawAmount',
|
||||
key: 'withdrawAmount',
|
||||
width: 120,
|
||||
align: 'right'
|
||||
},
|
||||
{
|
||||
title: '手续费',
|
||||
dataIndex: 'fee',
|
||||
key: 'fee',
|
||||
width: 100,
|
||||
align: 'right',
|
||||
render: fee => fee ? `${fee}元` : '-'
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
key: 'status',
|
||||
dataIndex: 'withdrawStatus',
|
||||
key: 'withdrawStatus',
|
||||
width: 100
|
||||
},
|
||||
{
|
||||
title: '申请时间',
|
||||
key: 'createdAt',
|
||||
width: 180
|
||||
},
|
||||
{
|
||||
title: '完成时间',
|
||||
key: 'completedAt',
|
||||
dataIndex: 'created_at',
|
||||
key: 'created_at',
|
||||
width: 180
|
||||
},
|
||||
{
|
||||
@ -189,10 +215,6 @@ const columns = [
|
||||
// 提现记录数据
|
||||
const withdrawalRecords = ref([])
|
||||
const loading = ref(false)
|
||||
const accountOptions = ref([
|
||||
{ value: '1', label: '工商银行(尾号5678)' },
|
||||
{ value: '2', label: '建设银行(尾号1234)' }
|
||||
])
|
||||
|
||||
// 提现弹窗
|
||||
const withdrawalModal = reactive({
|
||||
@ -204,14 +226,19 @@ const withdrawalModal = reactive({
|
||||
const withdrawalFormRef = ref()
|
||||
const withdrawalForm = reactive({
|
||||
amount: undefined,
|
||||
accountId: accountInfo.id
|
||||
accountId: ''
|
||||
})
|
||||
|
||||
// 表单验证规则
|
||||
const withdrawalRules = {
|
||||
amount: [
|
||||
{ required: true, message: '请输入提现金额' },
|
||||
{ type: 'number', min: 1, max: accountInfo.availableBalance, message: `提现金额需在1-${accountInfo.availableBalance}元之间` }
|
||||
{
|
||||
type: 'number',
|
||||
min: 1,
|
||||
max: accountInfo.availableBalance,
|
||||
message: `提现金额需在1-${accountInfo.availableBalance}元之间`
|
||||
}
|
||||
],
|
||||
accountId: [
|
||||
{ required: true, message: '请选择提现账户' }
|
||||
@ -226,33 +253,160 @@ onMounted(() => {
|
||||
const userInfoStr = localStorage.getItem("userInfo")
|
||||
if (userInfoStr) {
|
||||
const userInfo = JSON.parse(userInfoStr);
|
||||
accountInfo.availableBalance=userInfo.balance
|
||||
accountInfo.availableBalance = Number(userInfo.balance) || 0
|
||||
}
|
||||
fetchWithdrawalRecords()
|
||||
getUserBankInfo()
|
||||
})
|
||||
|
||||
// 获取提现记录
|
||||
const fetchWithdrawalRecords = async () => {
|
||||
loading.value = true
|
||||
console.log(searchParams)
|
||||
try {
|
||||
let params = {
|
||||
withdraw_number: searchParams.orderNo,
|
||||
withdraw_number: searchParams.orderNo || undefined,
|
||||
page_num: pagination.current,
|
||||
page_size: pagination.pageSize,
|
||||
start_at: formatDate(searchParams.dateRange[0]),
|
||||
end_at: formatDate(searchParams.dateRange[1]),
|
||||
page_size: pagination.pageSize
|
||||
}
|
||||
|
||||
// 添加日期参数
|
||||
if (searchParams.dateRange && searchParams.dateRange.length === 2) {
|
||||
params.start_at = formatDateForApi(searchParams.dateRange[0])
|
||||
params.end_at = formatDateForApi(searchParams.dateRange[1])
|
||||
}
|
||||
|
||||
const res = await getWithdrawList(params)
|
||||
console.log(res)
|
||||
console.log("提现记录接口返回:", res)
|
||||
|
||||
if (res && res.data && Array.isArray(res.data)) {
|
||||
console.log("提现记录数据:", res.data)
|
||||
// 处理数据并计算状态
|
||||
withdrawalRecords.value = res.data.map(item => ({
|
||||
...item,
|
||||
// 添加格式化后的状态文本,便于显示
|
||||
withdrawStatusText: getStatusText(item.withdrawStatus)
|
||||
}))
|
||||
pagination.total = res.total || 0
|
||||
} else {
|
||||
withdrawalRecords.value = []
|
||||
pagination.total = 0
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
console.error('获取提现记录失败:', error)
|
||||
message.error('获取提现记录失败')
|
||||
withdrawalRecords.value = []
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 为API格式化日期(去掉时间部分)
|
||||
const formatDateForApi = (date) => {
|
||||
if (!date) return ''
|
||||
return dayjs(date).format('YYYY-MM-DD')
|
||||
}
|
||||
|
||||
// 获取用户银行卡信息
|
||||
const getUserBankInfo = async () => {
|
||||
bankLoading.value = true
|
||||
try {
|
||||
const res = await getBankCardInfo()
|
||||
console.log('银行卡信息:', res)
|
||||
|
||||
if (res) {
|
||||
// 根据接口返回的数据结构处理
|
||||
const bankData = res
|
||||
|
||||
// 判断返回的是单个对象还是数组
|
||||
if (Array.isArray(bankData)) {
|
||||
bankCards.value = bankData.map(bank => ({
|
||||
id: bank.id,
|
||||
bankCardNo: bank.bank_card_no,
|
||||
name: bank.name,
|
||||
phone: bank.phone,
|
||||
// 假设银行名称,你可以根据卡号前几位判断银行
|
||||
bankName: getBankName(bank.bank_card_no)
|
||||
}))
|
||||
} else {
|
||||
// 单个对象的情况
|
||||
bankCards.value = [{
|
||||
id: bankData.id,
|
||||
bankCardNo: bankData.bank_card_no,
|
||||
name: bankData.name,
|
||||
phone: bankData.phone,
|
||||
bankName: getBankName(bankData.bank_card_no)
|
||||
}]
|
||||
}
|
||||
|
||||
// 如果有银行卡数据,设置默认选中第一个
|
||||
if (bankCards.value.length > 0) {
|
||||
withdrawalForm.accountId = bankCards.value[0].id
|
||||
}
|
||||
} else {
|
||||
bankCards.value = []
|
||||
message.error('获取银行卡信息失败')
|
||||
}
|
||||
} catch (error) {
|
||||
console.log('获取银行卡信息失败:', error)
|
||||
bankCards.value = []
|
||||
message.error('获取银行卡信息失败')
|
||||
} finally {
|
||||
bankLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 根据卡号获取银行名称(简化版)
|
||||
const getBankName = (cardNo) => {
|
||||
if (!cardNo) return '未知银行'
|
||||
|
||||
// 这里根据卡号前几位判断银行,实际项目中需要更完善的判断逻辑
|
||||
const firstDigits = cardNo.substring(0, 6)
|
||||
const bankMapping = {
|
||||
'622848': '中国农业银行',
|
||||
'622700': '中国建设银行',
|
||||
'622208': '中国工商银行',
|
||||
'622622': '中国银行',
|
||||
'622588': '招商银行',
|
||||
'622909': '兴业银行',
|
||||
'622516': '平安银行',
|
||||
'622538': '浦发银行',
|
||||
'622680': '民生银行',
|
||||
'622568': '广发银行',
|
||||
'622888': '中信银行'
|
||||
}
|
||||
|
||||
for (const [prefix, bankName] of Object.entries(bankMapping)) {
|
||||
if (cardNo.startsWith(prefix)) {
|
||||
return bankName
|
||||
}
|
||||
}
|
||||
|
||||
return '银行卡'
|
||||
}
|
||||
|
||||
// 获取银行卡显示文本
|
||||
const getBankCardDisplay = (bank) => {
|
||||
if (!bank) return ''
|
||||
|
||||
const bankName = bank.bankName || '银行卡'
|
||||
const maskedCardNo = maskCardNumber(bank.bankCardNo)
|
||||
const userName = bank.name || ''
|
||||
|
||||
return `${bankName} (${maskedCardNo}) ${userName}`
|
||||
}
|
||||
|
||||
// 隐藏银行卡中间部分
|
||||
const maskCardNumber = (cardNo) => {
|
||||
if (!cardNo) return ''
|
||||
if (cardNo.length <= 8) return cardNo
|
||||
|
||||
const first4 = cardNo.substring(0, 4)
|
||||
const last4 = cardNo.substring(cardNo.length - 4)
|
||||
const masked = '*'.repeat(Math.max(0, cardNo.length - 8))
|
||||
|
||||
return `${first4}${masked}${last4}`
|
||||
}
|
||||
|
||||
// 表格分页变化
|
||||
const handleTableChange = (page) => {
|
||||
pagination.current = page.current
|
||||
@ -269,8 +423,6 @@ const handleSearch = () => {
|
||||
// 重置查询
|
||||
const handleReset = () => {
|
||||
searchParams.orderNo = ''
|
||||
searchParams.account = undefined
|
||||
searchParams.status = undefined
|
||||
searchParams.dateRange = [dayjs().subtract(30, 'day'), dayjs()]
|
||||
handleSearch()
|
||||
}
|
||||
@ -282,6 +434,10 @@ const handleDateChange = () => {
|
||||
|
||||
// 显示提现弹窗
|
||||
const showWithdrawalModal = () => {
|
||||
// 每次打开弹窗时重新获取银行卡信息
|
||||
if (bankCards.value.length === 0) {
|
||||
getUserBankInfo()
|
||||
}
|
||||
withdrawalModal.visible = true
|
||||
}
|
||||
|
||||
@ -289,11 +445,24 @@ const showWithdrawalModal = () => {
|
||||
const handleWithdrawalSubmit = async () => {
|
||||
try {
|
||||
await withdrawalFormRef.value.validate()
|
||||
|
||||
// 检查是否选择了银行卡
|
||||
if (!withdrawalForm.accountId) {
|
||||
message.error('请选择提现账户')
|
||||
return
|
||||
}
|
||||
|
||||
// 获取选中的银行卡信息
|
||||
const selectedBank = bankCards.value.find(bank => bank.id === withdrawalForm.accountId)
|
||||
if (!selectedBank) {
|
||||
message.error('选择的银行卡信息不存在')
|
||||
return
|
||||
}
|
||||
|
||||
withdrawalModal.confirming = true
|
||||
|
||||
// 模拟API调用
|
||||
await new Promise(resolve => setTimeout(resolve, 1000))
|
||||
|
||||
// 调用提现API
|
||||
await getWithdraw({ amount: withdrawalForm.amount });
|
||||
message.success('提现申请提交成功')
|
||||
|
||||
// 更新账户余额
|
||||
@ -307,6 +476,11 @@ const handleWithdrawalSubmit = async () => {
|
||||
fetchWithdrawalRecords()
|
||||
} catch (error) {
|
||||
console.error('提现提交失败:', error)
|
||||
if (error.errorFields) {
|
||||
message.error('请检查表单填写是否正确')
|
||||
} else {
|
||||
message.error(error.message || '提现提交失败')
|
||||
}
|
||||
} finally {
|
||||
withdrawalModal.confirming = false
|
||||
}
|
||||
@ -314,49 +488,37 @@ const handleWithdrawalSubmit = async () => {
|
||||
|
||||
// 处理提现取消
|
||||
const handleWithdrawalCancel = () => {
|
||||
if (withdrawalFormRef.value) {
|
||||
withdrawalFormRef.value.resetFields()
|
||||
}
|
||||
withdrawalModal.visible = false
|
||||
}
|
||||
|
||||
// 查看详情
|
||||
const viewDetail = (record) => {
|
||||
message.info(`查看提现记录详情: ${record.orderNo}`)
|
||||
message.info(`查看提现记录详情: ${record.withdraw_number}`)
|
||||
// 这里可以打开详情弹窗或跳转到详情页面
|
||||
}
|
||||
|
||||
// 计算实际到账金额
|
||||
const calculateActualAmount = (amount) => {
|
||||
const fee = amount * 0.01 // 假设手续费1%
|
||||
return amount - fee
|
||||
}
|
||||
|
||||
// 格式化货币
|
||||
// 格式化货币 - 修复错误
|
||||
const formatCurrency = (amount) => {
|
||||
return amount.toFixed(2).replace(/\d(?=(\d{3})+\.)/g, '$&,')
|
||||
// 处理 null、undefined 和非数值的情况
|
||||
if (amount === null || amount === undefined || isNaN(amount)) {
|
||||
return '0.00'
|
||||
}
|
||||
|
||||
const num = Number(amount)
|
||||
if (isNaN(num)) {
|
||||
return '0.00'
|
||||
}
|
||||
|
||||
return num.toFixed(2).replace(/\d(?=(\d{3})+\.)/g, '$&,')
|
||||
}
|
||||
|
||||
// 格式化日期
|
||||
const formatDate = (dateString) => {
|
||||
return dayjs(dateString).format('YYYY-MM-DD')
|
||||
}
|
||||
|
||||
// 获取状态颜色
|
||||
const getStatusColor = (status) => {
|
||||
const colors = {
|
||||
pending: 'orange',
|
||||
success: 'green',
|
||||
failed: 'red'
|
||||
}
|
||||
return colors[status] || 'default'
|
||||
}
|
||||
|
||||
// 获取状态文本
|
||||
const getStatusText = (status) => {
|
||||
const texts = {
|
||||
pending: '处理中',
|
||||
success: '成功',
|
||||
failed: '失败'
|
||||
}
|
||||
return texts[status] || status
|
||||
if (!dateString) return ''
|
||||
return dayjs(dateString).format('YYYY-MM-DD HH:mm:ss')
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -442,4 +604,33 @@ const getStatusText = (status) => {
|
||||
float: inline-end;
|
||||
width: 10%;
|
||||
}
|
||||
|
||||
/* 状态标签样式 */
|
||||
:deep(.ant-tag) {
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
:deep(.ant-tag-orange) {
|
||||
background: #fff7e6;
|
||||
border-color: #ffd591;
|
||||
color: #fa8c16;
|
||||
}
|
||||
|
||||
:deep(.ant-tag-blue) {
|
||||
background: #e6f4ff;
|
||||
border-color: #91caff;
|
||||
color: #1677ff;
|
||||
}
|
||||
|
||||
:deep(.ant-tag-green) {
|
||||
background: #f6ffed;
|
||||
border-color: #b7eb8f;
|
||||
color: #52c41a;
|
||||
}
|
||||
|
||||
:deep(.ant-tag-red) {
|
||||
background: #fff2f0;
|
||||
border-color: #ffccc7;
|
||||
color: #ff4d4f;
|
||||
}
|
||||
</style>
|
||||
@ -83,15 +83,40 @@ import {
|
||||
invoiceList,
|
||||
invoiceDetail
|
||||
} from '@/apis/admin'
|
||||
import { Tag } from 'ant-design-vue'
|
||||
|
||||
// 发票状态枚举映射
|
||||
const INVOICE_STATUS_MAP = {
|
||||
'InvoiceProcessing': { text: '开票中', color: 'processing' },
|
||||
'InvoiceSuccessful': { text: '开票成功', color: 'success' },
|
||||
'InvoiceFailed': { text: '开票失败', color: 'error' },
|
||||
'InvoiceRejected': { text: '已驳回', color: 'warning' },
|
||||
'PendingReview': { text: '待审核', color: 'warning' },
|
||||
'ReviewFailed': { text: '审核失败', color: 'warning' },
|
||||
'PendingInvoice': { text: '待开票(审核成功)', color: 'warning' },
|
||||
'PendingSend': { text: '待寄送(开票成功)', color: 'warning' },
|
||||
'SendSuccessful': { text: '寄送完成', color: 'warning' },
|
||||
'SendFailed': { text: '寄送失败', color: 'warning' }
|
||||
}
|
||||
|
||||
// 获取发票状态显示文本
|
||||
const getInvoiceStatusText = (status: string) => {
|
||||
return INVOICE_STATUS_MAP[status as keyof typeof INVOICE_STATUS_MAP]?.text || status
|
||||
}
|
||||
|
||||
// 获取发票状态颜色
|
||||
const getInvoiceStatusColor = (status: string) => {
|
||||
return INVOICE_STATUS_MAP[status as keyof typeof INVOICE_STATUS_MAP]?.color || 'default'
|
||||
}
|
||||
|
||||
// 发票状态渲染组件
|
||||
const InvoiceStatusTag = ({ status }: { status: string }) => {
|
||||
const statusInfo = INVOICE_STATUS_MAP[status as keyof typeof INVOICE_STATUS_MAP]
|
||||
if (!statusInfo) return status
|
||||
|
||||
return h(Tag, { color: statusInfo.color }, () => statusInfo.text)
|
||||
}
|
||||
|
||||
// const listData=ref([ {title:1}])
|
||||
// const paginationState=ref({
|
||||
// total: 0,
|
||||
// current: 1,
|
||||
// pageSize: 10,
|
||||
// showTotal: (total) => `总 ${total} 条数据`,
|
||||
// pageSizeOptions: ['10', '20', '30', '40'],
|
||||
// })
|
||||
const { listData, loading, showLoading, hideLoading, paginationState, resetPagination, searchFormData } = usePagination()
|
||||
const visibleOpen = ref(false)
|
||||
const formData = ref<any>({ type: 'a' })
|
||||
@ -104,7 +129,7 @@ const rules = computed(() => ({
|
||||
recipientAddress: [{ required: true, message: '请选择收件人地址', trigger: 'change' }],
|
||||
number: [
|
||||
{
|
||||
required: formData.value.type === 'b', // 只有“增值税专用发票”(value='b')才必填
|
||||
required: formData.value.type === 'b', // 只有"增值税专用发票"(value='b')才必填
|
||||
message: '请输入纳税人识别号',
|
||||
trigger: 'blur'
|
||||
}
|
||||
@ -138,6 +163,7 @@ const rules = computed(() => ({
|
||||
}
|
||||
]
|
||||
}))
|
||||
|
||||
const columns = ref([
|
||||
{ title: '申请时间', dataIndex: 'invoiceDate', key: 'invoiceDate' },
|
||||
{ title: '开票内容', dataIndex: 'invoiceContent', key: 'invoiceContent' },
|
||||
@ -145,35 +171,72 @@ const columns = ref([
|
||||
{ title: '发票总额', dataIndex: 'invoiceAmount', key: 'invoiceAmount' },
|
||||
{ title: '开票方式', dataIndex: 'invoiceMethod', key: 'invoiceMethod' },
|
||||
{ title: '发票类型', dataIndex: 'invoiceType', key: 'invoiceType' },
|
||||
{ title: '发票状态', dataIndex: 'invoiceStatus', key: 'invoiceStatus' },
|
||||
{
|
||||
title: '发票状态',
|
||||
dataIndex: 'invoiceStatus',
|
||||
key: 'invoiceStatus',
|
||||
customRender: ({ text: status }) => {
|
||||
const statusInfo = INVOICE_STATUS_MAP[status as keyof typeof INVOICE_STATUS_MAP]
|
||||
if (!statusInfo) return status
|
||||
|
||||
// 创建简单的 span 元素显示状态
|
||||
const span = document.createElement('span')
|
||||
span.className = `invoice-status invoice-status-${statusInfo.color}`
|
||||
span.textContent = statusInfo.text
|
||||
return {
|
||||
children: statusInfo.text,
|
||||
props: {
|
||||
class: `invoice-status invoice-status-${statusInfo.color}`
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{ title: '驳回原因', dataIndex: 'rejectReason', key: 'rejectReason' },
|
||||
{ title: '操作', dataIndex: 'flowNum', key: 'flowNum' },
|
||||
])
|
||||
|
||||
onBeforeMount(() => {
|
||||
getPageList()
|
||||
|
||||
})
|
||||
|
||||
const getPageList = async () => {
|
||||
try {
|
||||
const params = {
|
||||
page_num: 1,
|
||||
page_size: 10, // 获取足够多的数据来统计
|
||||
page_size: 10,
|
||||
};
|
||||
|
||||
const response: any = await invoiceList(params);
|
||||
|
||||
if (response.data && Array.isArray(response.data)) {
|
||||
listData.value = response.data
|
||||
console.log('发票列表:', response.data);
|
||||
// 转换发票状态为可读文本(如果需要)
|
||||
const transformedData = response.data.map(item => ({
|
||||
...item,
|
||||
// 如果需要在前端显示时转换,可以在这里添加
|
||||
// invoiceStatusText: getInvoiceStatusText(item.invoiceStatus)
|
||||
}))
|
||||
|
||||
listData.value = transformedData
|
||||
console.log('发票列表:', transformedData);
|
||||
}
|
||||
|
||||
|
||||
} catch (error) {
|
||||
console.error('获取全部消息失败:', error);
|
||||
console.error('获取发票列表失败:', error);
|
||||
listData.value = [];
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 处理数据映射 - 如果需要显示时转换
|
||||
*/
|
||||
const processInvoiceData = (data) => {
|
||||
return data.map(item => ({
|
||||
...item,
|
||||
// 这里可以添加其他字段的转换
|
||||
invoiceStatusText: getInvoiceStatusText(item.invoiceStatus)
|
||||
}))
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页
|
||||
*/
|
||||
@ -182,6 +245,7 @@ function onTableChange({ current, pageSize }) {
|
||||
paginationState.pageSize = pageSize
|
||||
getPageList()
|
||||
}
|
||||
|
||||
/**
|
||||
* 搜索
|
||||
*/
|
||||
@ -189,6 +253,7 @@ function handleSearch() {
|
||||
resetPagination()
|
||||
getPageList()
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置
|
||||
*/
|
||||
@ -197,20 +262,47 @@ function handleResetSearch() {
|
||||
resetPagination()
|
||||
getPageList()
|
||||
}
|
||||
|
||||
function handleOk() {
|
||||
visibleOpen.value = false
|
||||
|
||||
formRef.value.validateFields().then(async (values) => {
|
||||
try {
|
||||
|
||||
// 提交逻辑
|
||||
} catch (error) {
|
||||
|
||||
console.error('提交失败:', error);
|
||||
}
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.bold {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
// 可以添加一些自定义样式
|
||||
:deep(.ant-tag-processing) {
|
||||
background: #e6f4ff;
|
||||
border-color: #91caff;
|
||||
color: #1677ff;
|
||||
}
|
||||
|
||||
:deep(.ant-tag-success) {
|
||||
background: #f6ffed;
|
||||
border-color: #b7eb8f;
|
||||
color: #52c41a;
|
||||
}
|
||||
|
||||
:deep(.ant-tag-error) {
|
||||
background: #fff2f0;
|
||||
border-color: #ffccc7;
|
||||
color: #ff4d4f;
|
||||
}
|
||||
|
||||
:deep(.ant-tag-warning) {
|
||||
background: #fff7e6;
|
||||
border-color: #ffd591;
|
||||
color: #fa8c16;
|
||||
}
|
||||
</style>
|
||||
@ -13,7 +13,7 @@
|
||||
:loading="loading" class="bill-table" :scroll="{ x: 1200 }" bordered>
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.key === 'status'">
|
||||
<a-tag v-if="record.status === 'enabled'" color="green">有效</a-tag>
|
||||
<a-tag v-if="record.status === '可用'" color="green">可用</a-tag>
|
||||
<a-tag v-else color="red">失效</a-tag>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
@ -100,7 +100,8 @@
|
||||
<div>算力券:</div>
|
||||
<a-select ref="select" v-model:value="voucherId" style="width:300px" @change="handleChange">
|
||||
<a-select-option :value="''">不使用算力券</a-select-option>
|
||||
<a-select-option v-for="value in voucherList" :value="value.id">{{ value.name + ' - '+'¥'+value.amount }}</a-select-option>
|
||||
<a-select-option v-for="value in voucherList" :value="value.id">{{ formatVoucherLabel(value)
|
||||
}}</a-select-option>
|
||||
</a-select>
|
||||
</div>
|
||||
|
||||
@ -249,10 +250,53 @@ const getServiceImages = async () => {
|
||||
try {
|
||||
selectedImage.value = ''
|
||||
const res = await getImages({ image_type: imageType.value })
|
||||
console.log(res.data)
|
||||
imageOptions.value = res.data.map((item: any) => ({ id: item.id, label: item.image_name }))
|
||||
} catch (error) {
|
||||
console.log("API返回数据:", res)
|
||||
|
||||
if (res.data && Array.isArray(res.data.data) && res.data.data.length > 0) {
|
||||
console.log("情况1: data.data是数组且有数据")
|
||||
imageOptions.value = res.data.data.map((item: any) => ({
|
||||
id: item.id,
|
||||
label: item.image_name
|
||||
}))
|
||||
}
|
||||
|
||||
else if (res.data && res.data.data === null) {
|
||||
console.log("情况2: data.data是null")
|
||||
imageOptions.value = []
|
||||
if (imageType.value === 'USER') {
|
||||
console.log("用户没有自定义镜像")
|
||||
// 可以添加一个提示,但不是必须的
|
||||
}
|
||||
}
|
||||
|
||||
else if (res.data && Array.isArray(res.data.data) && res.data.data.length === 0) {
|
||||
console.log("情况3: data.data是空数组")
|
||||
imageOptions.value = []
|
||||
if (imageType.value === 'USER') {
|
||||
console.log("用户的自定义镜像列表为空")
|
||||
}
|
||||
}
|
||||
|
||||
else if (Array.isArray(res.data)) {
|
||||
console.log("情况4: res.data直接是数组")
|
||||
imageOptions.value = res.data.map((item: any) => ({
|
||||
id: item.id,
|
||||
label: item.image_name
|
||||
}))
|
||||
}
|
||||
|
||||
else {
|
||||
console.log("情况5: 未知数据格式", res.data)
|
||||
imageOptions.value = []
|
||||
}
|
||||
|
||||
|
||||
console.log("最终的imageOptions:", imageOptions.value)
|
||||
|
||||
} catch (error) {
|
||||
console.error("获取镜像失败:", error)
|
||||
message.error('获取镜像列表失败')
|
||||
imageOptions.value = []
|
||||
}
|
||||
}
|
||||
|
||||
@ -280,9 +324,15 @@ const handleCreate = async () => {
|
||||
voucher_id: voucherId.value
|
||||
}
|
||||
const res = await createHost(params)
|
||||
if (res == null) {
|
||||
return false;
|
||||
} else {
|
||||
message.success('实例创建成功!')
|
||||
creating.value = false
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('创建失败:', error)
|
||||
message.error('创建失败,请重试')
|
||||
} finally {
|
||||
creating.value = false
|
||||
@ -293,6 +343,10 @@ const handleCancel = () => {
|
||||
window.history.back()
|
||||
}
|
||||
|
||||
const formatVoucherLabel = (voucher: any) => {
|
||||
return `${voucher.name} - ¥${voucher.amount}`
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
@ -67,6 +67,11 @@ const formState = reactive<FormState>({
|
||||
invite_id: '',
|
||||
});
|
||||
|
||||
// Register.vue
|
||||
const emit = defineEmits<{
|
||||
(e: 'register-success'): void;
|
||||
}>();
|
||||
|
||||
const clearCodeError = () => {
|
||||
codeValidateStatus.value = '';
|
||||
codeHelp.value = '';
|
||||
@ -82,22 +87,29 @@ const querenPassword = (rule, value) => {
|
||||
}
|
||||
return Promise.resolve();
|
||||
};
|
||||
|
||||
const onFinish = async (values: FormState) => {
|
||||
clearCodeError();
|
||||
const loginData = {
|
||||
...values,
|
||||
checked: checked.value,
|
||||
};
|
||||
formRef.value?.validateFields().then(async () => {
|
||||
try {
|
||||
await formRef.value?.validateFields();
|
||||
const res: any = await apis.login.register(loginData);
|
||||
console.log('注册请求成功:', res);
|
||||
message.success('注册成功,请登录');
|
||||
message.success('注册成功,即将返回登陆界面');
|
||||
|
||||
setTimeout(() => {
|
||||
emit('register-success');
|
||||
}, 2000);
|
||||
|
||||
|
||||
formRef.value?.resetFields();
|
||||
} catch (error: any) {
|
||||
console.error('注册请求失败:', error);
|
||||
message.error(error);
|
||||
message.error(error?.response?.data?.message || '注册失败,请稍后重试');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const onFinishFailed = (errorInfo: any) => {
|
||||
|
||||
@ -40,7 +40,7 @@
|
||||
</div>
|
||||
<div v-if="currentTag == 'register'">
|
||||
<div>
|
||||
<Register />
|
||||
<Register @register-success="handleRegisterSuccess"/>
|
||||
<div style="text-align: right;">
|
||||
<span style="color: #666;cursor: pointer;font-size: 14px;" @click="currentTag = 'login'">
|
||||
已有账号?去 <span style="color: #1677ff;">登录</span></span>
|
||||
@ -111,6 +111,10 @@ const handleMenuClick = (key) => {
|
||||
router.push(fullPath);
|
||||
}
|
||||
}
|
||||
|
||||
const handleRegisterSuccess = () => {
|
||||
currentTag.value = 'login'; // 切换回登录 tab
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
@ -132,10 +132,17 @@ const currentPage = ref(1)
|
||||
const pageSize = ref(10)
|
||||
onMounted(async () => {
|
||||
spinning.value = true
|
||||
await getHostList()
|
||||
try {
|
||||
// 先获取地区和GPU列表
|
||||
await getAreaList()
|
||||
await getGpuList()
|
||||
// 再获取主机列表
|
||||
await getHostList()
|
||||
} catch (error) {
|
||||
console.error('初始化失败:', error)
|
||||
} finally {
|
||||
spinning.value = false
|
||||
}
|
||||
})
|
||||
|
||||
async function getHostList() {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user