存款,存款渠道,充值订单
This commit is contained in:
parent
f5b3faa318
commit
44e43d81f3
|
|
@ -0,0 +1,18 @@
|
||||||
|
import { request } from '@/api'
|
||||||
|
|
||||||
|
// 获取入金渠道列表
|
||||||
|
export const getChannelList = () => {
|
||||||
|
return request.get('/channel/getChannelList')
|
||||||
|
}
|
||||||
|
// 创建入金渠道列表
|
||||||
|
export const createChannel = (params: any) => {
|
||||||
|
return request.post('/channel/createChannel', { ...params })
|
||||||
|
}
|
||||||
|
// 编辑入金渠道列表
|
||||||
|
export const editChannel = (params: any) => {
|
||||||
|
return request.post('/channel/editChannel', { ...params })
|
||||||
|
}
|
||||||
|
// 删除入金渠道列表
|
||||||
|
export const delChannel = (params: any) => {
|
||||||
|
return request.post('/channel/delChannel', { ...params })
|
||||||
|
}
|
||||||
|
|
@ -4,3 +4,7 @@ import { request } from '@/api';
|
||||||
export const getRechargeCheckListApi = (params: any) => {
|
export const getRechargeCheckListApi = (params: any) => {
|
||||||
return request.get('/user/rechargeReviewList', { ...params })
|
return request.get('/user/rechargeReviewList', { ...params })
|
||||||
}
|
}
|
||||||
|
// 充值审核
|
||||||
|
export const reviewRechargeOrder = (params: any) => {
|
||||||
|
return request.post('/user/reviewRechargeOrder', { ...params })
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
import { request } from '@/api'
|
||||||
|
|
||||||
|
// 获取充值订单列表
|
||||||
|
export const getRechargeOrderListApi = (params: any) => {
|
||||||
|
return request.get('/user/rechargeList', { ...params })
|
||||||
|
}
|
||||||
|
|
||||||
|
// 审核充值订单
|
||||||
|
export const reviewRechargeOrder = (params: any) => {
|
||||||
|
return request.post('/user/reviewRechargeOrder', { ...params })
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,6 +0,0 @@
|
||||||
import { request } from '@/api';
|
|
||||||
|
|
||||||
// 获取充值订单列表
|
|
||||||
export const getRechargeOrderListApi = (params: any) => {
|
|
||||||
return request.get('/user/rechargeList', { ...params })
|
|
||||||
}
|
|
||||||
|
|
@ -30,7 +30,7 @@
|
||||||
show-password
|
show-password
|
||||||
type="password"
|
type="password"
|
||||||
/>
|
/>
|
||||||
<!-- 密码输入框 -->
|
<!-- 长文本输入框 -->
|
||||||
<el-input
|
<el-input
|
||||||
v-else-if="item.type === 'textarea'"
|
v-else-if="item.type === 'textarea'"
|
||||||
v-model="formData[item.prop]"
|
v-model="formData[item.prop]"
|
||||||
|
|
@ -75,6 +75,8 @@
|
||||||
:max="item.max"
|
:max="item.max"
|
||||||
:placeholder="item.placeholder"
|
:placeholder="item.placeholder"
|
||||||
:disabled="item.disabled"
|
:disabled="item.disabled"
|
||||||
|
:controls="item.controls ?? true"
|
||||||
|
:align="item.align || 'left'"
|
||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
@ -175,6 +177,8 @@ interface FormItem {
|
||||||
clearable?: boolean
|
clearable?: boolean
|
||||||
disabledDate?: (time: Date) => boolean
|
disabledDate?: (time: Date) => boolean
|
||||||
isRange?: boolean
|
isRange?: boolean
|
||||||
|
controls?: boolean
|
||||||
|
align?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
|
|
|
||||||
|
|
@ -1,70 +1,106 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="table-container">
|
<div class="table-container">
|
||||||
<el-table height="100%" :data="tableData" :row-key="rowKey" :tree-props="treeProps" :border="border"
|
<el-table
|
||||||
:highlight-current-row="highlightCurrentRow" v-bind="$attrs" @row-click="handleRowClick">
|
ref="tableRef"
|
||||||
<!-- 动态表头列 -->
|
height="100%"
|
||||||
<template v-for="(column, index) in columns" :key="index">
|
:data="tableData"
|
||||||
<el-table-column v-if="!column.slotName" :prop="column.prop" :label="column.label" :width="column.width"
|
:row-key="rowKey"
|
||||||
:align="column.align || 'left'" :sortable="column.sortable" />
|
:tree-props="treeProps"
|
||||||
|
:border="border"
|
||||||
|
:highlight-current-row="highlightCurrentRow"
|
||||||
|
v-bind="$attrs"
|
||||||
|
@row-click="handleRowClick"
|
||||||
|
>
|
||||||
|
<!-- 动态表头列 -->
|
||||||
|
<template v-for="(column, index) in columns" :key="index">
|
||||||
|
<el-table-column
|
||||||
|
v-if="column.type === 'index'"
|
||||||
|
type="index"
|
||||||
|
:label="column.label"
|
||||||
|
:width="column.width || 60"
|
||||||
|
:align="column.align || 'center'"
|
||||||
|
/>
|
||||||
|
<el-table-column
|
||||||
|
v-else-if="!column.slotName"
|
||||||
|
:prop="column.prop"
|
||||||
|
:label="column.label"
|
||||||
|
:width="column.width"
|
||||||
|
:align="column.align || 'left'"
|
||||||
|
:sortable="column.sortable"
|
||||||
|
/>
|
||||||
|
|
||||||
<!-- 具名插槽列 -->
|
<!-- 具名插槽列 -->
|
||||||
<el-table-column v-else :label="column.label" :width="column.width" :align="column.align || 'left'">
|
<el-table-column
|
||||||
<template #default="{ row }">
|
v-else
|
||||||
<slot :name="column.slotName" :row="row" />
|
:label="column.label"
|
||||||
</template>
|
:width="column.width"
|
||||||
</el-table-column>
|
:align="column.align || 'left'"
|
||||||
</template>
|
>
|
||||||
</el-table>
|
<template #default="{ row }">
|
||||||
</div>
|
<slot :name="column.slotName" :row="row" />
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</template>
|
||||||
|
</el-table>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import type { TableInstance } from 'element-plus'
|
||||||
// 定义表格列配置接口
|
// 定义表格列配置接口
|
||||||
interface TableColumn {
|
interface TableColumn {
|
||||||
prop?: string
|
prop?: string
|
||||||
label: string
|
type?: string
|
||||||
width?: string | number
|
label: string
|
||||||
align?: 'left' | 'center' | 'right'
|
width?: string | number
|
||||||
slotName?: string // 具名插槽名称
|
align?: 'left' | 'center' | 'right'
|
||||||
sortable?: boolean // 是否可排序
|
slotName?: string // 具名插槽名称
|
||||||
|
sortable?: boolean // 是否可排序
|
||||||
}
|
}
|
||||||
|
|
||||||
// 定义表格组件属性接口
|
// 定义表格组件属性接口
|
||||||
interface Props {
|
interface Props {
|
||||||
tableData: any[]
|
tableData: any[]
|
||||||
rowKey?: string
|
rowKey?: string
|
||||||
treeProps?: {
|
treeProps?: {
|
||||||
children: string
|
children: string
|
||||||
}
|
}
|
||||||
columns?: TableColumn[],
|
columns?: TableColumn[]
|
||||||
border?: boolean // 是否显示边框
|
border?: boolean // 是否显示边框
|
||||||
highlightCurrentRow?: boolean // 是否高亮当前行
|
highlightCurrentRow?: boolean // 是否高亮当前行
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = withDefaults(defineProps<Props>(), {
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
border: true,
|
border: true,
|
||||||
highlightCurrentRow: true,
|
highlightCurrentRow: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
// 定义组件抛出的事件
|
// 定义组件抛出的事件
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(e: 'row-click', row: any): void // 保留原有行点击事件
|
(e: 'row-click', row: any): void // 保留原有行点击事件
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 处理行点击事件(兼容原有逻辑)
|
* 处理行点击事件(兼容原有逻辑)
|
||||||
*/
|
*/
|
||||||
const handleRowClick = (row: any) => {
|
const handleRowClick = (row: any) => {
|
||||||
// 增加空值保护,避免传递 null 给父组件
|
// 增加空值保护,避免传递 null 给父组件
|
||||||
if (!row) return
|
if (!row) return
|
||||||
emit('row-click', row)
|
emit('row-click', row)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const tableRef = ref<TableInstance>()
|
||||||
|
|
||||||
|
// 暴露清除当前选中行的方法
|
||||||
|
defineExpose({
|
||||||
|
clearCurrentRow: () => tableRef.value?.setCurrentRow(),
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.table-container {
|
.table-container {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: calc(100vh - 180px);
|
height: calc(100vh - 180px);
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
/**
|
||||||
|
* 获取近七天的开始和结束时间
|
||||||
|
* @param format 日期格式,默认 'YYYY-MM-DD HH:mm:ss'
|
||||||
|
* YYYY - 年, MM - 月, DD - 日, HH - 时, mm - 分, ss - 秒
|
||||||
|
* @returns { start: string, end: string }
|
||||||
|
*/
|
||||||
|
export const getRecentSevenDays = (format = 'YYYY-MM-DD HH:mm:ss'):{ start: string, end: string } => {
|
||||||
|
const now = new Date()
|
||||||
|
const sevenDaysAgo = new Date(now)
|
||||||
|
sevenDaysAgo.setDate(now.getDate() - 7)
|
||||||
|
|
||||||
|
const formatDateTime = (date: Date) => {
|
||||||
|
const tokens: Record<string, string> = {
|
||||||
|
YYYY: String(date.getFullYear()),
|
||||||
|
MM: String(date.getMonth() + 1).padStart(2, '0'),
|
||||||
|
DD: String(date.getDate()).padStart(2, '0'),
|
||||||
|
HH: String(date.getHours()).padStart(2, '0'),
|
||||||
|
mm: String(date.getMinutes()).padStart(2, '0'),
|
||||||
|
ss: String(date.getSeconds()).padStart(2, '0'),
|
||||||
|
}
|
||||||
|
let result = format
|
||||||
|
for (const [token, value] of Object.entries(tokens)) {
|
||||||
|
result = result.replace(token, value)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
start: formatDateTime(sevenDaysAgo),
|
||||||
|
end: formatDateTime(now),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,34 +1,188 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="deposit-channel">
|
<div class="deposit-channel">
|
||||||
<div class="bar">
|
<div class="bar">
|
||||||
<el-button type="primary" @click="handleAdd">添加</el-button>
|
<el-button type="primary" @click="handleAdd">添加</el-button>
|
||||||
<el-button type="danger" @click="handleEnable">启用</el-button>
|
<el-button type="primary" @click="handleEdit">编辑</el-button>
|
||||||
<el-button type="danger" @click="handleDisable">禁用</el-button>
|
<el-button type="danger" @click="handleDelete">删除</el-button>
|
||||||
</div>
|
|
||||||
<DepositChannelTable :table-data="tableTree" :columns="tableColumnsOptions" row-key="id"/>
|
|
||||||
</div>
|
</div>
|
||||||
|
<DepositChannelTable
|
||||||
|
ref="tableRef"
|
||||||
|
:table-data="tableData"
|
||||||
|
:columns="tableColumnsOptions"
|
||||||
|
row-key="id"
|
||||||
|
@rowClick="handleRowClick"
|
||||||
|
/>
|
||||||
|
<el-dialog
|
||||||
|
v-model="dialogVisible"
|
||||||
|
:title="dialogTitleType === 1 ? '添加充值渠道' : '编辑充值渠道'"
|
||||||
|
width="700"
|
||||||
|
>
|
||||||
|
<Form
|
||||||
|
:formItems="formItems"
|
||||||
|
:formRules="formRules"
|
||||||
|
:formData="formData"
|
||||||
|
:optionsMap="optionsMap"
|
||||||
|
/>
|
||||||
|
<template #footer>
|
||||||
|
<div class="dialog-footer">
|
||||||
|
<el-button @click="dialogVisible = false">取消</el-button>
|
||||||
|
<el-button type="primary" @click="submitDetail">确认</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
//组件
|
//组件
|
||||||
import DepositChannelTable from '@/components/common/Table.vue'
|
import DepositChannelTable from '@/components/common/Table.vue'
|
||||||
import { tableColumns } from './options'
|
import Form from '@/components/common/Form.vue'
|
||||||
|
import { tableColumns, formItemsData, formRulesData, optionsMapData } from './options'
|
||||||
|
import {
|
||||||
|
getChannelList,
|
||||||
|
createChannel,
|
||||||
|
editChannel,
|
||||||
|
delChannel,
|
||||||
|
} from '@/api/modules/capital/rechangeChanl.ts'
|
||||||
|
import { ElMessageBox } from 'element-plus'
|
||||||
|
|
||||||
|
type ChannelType = {
|
||||||
|
id?: number
|
||||||
|
name: string
|
||||||
|
channel_fee: number | null
|
||||||
|
type: number | null
|
||||||
|
api_url: string
|
||||||
|
api_appid: string
|
||||||
|
api_key: string
|
||||||
|
status: number
|
||||||
|
}
|
||||||
|
|
||||||
|
const getTypeText = (type: number | string) => {
|
||||||
|
return ['', '法币', '数字货币'][type]
|
||||||
|
}
|
||||||
|
|
||||||
|
const getStatusText = (status: number | string) => {
|
||||||
|
return ['', '正常', '禁用'][status]
|
||||||
|
}
|
||||||
|
|
||||||
|
const initData = async () => {
|
||||||
|
const res = await getChannelList()
|
||||||
|
console.log(res)
|
||||||
|
tableData.value = res.map((item: ChannelType) => ({
|
||||||
|
...item,
|
||||||
|
typeStr: getTypeText(item.type),
|
||||||
|
statusStr: getStatusText(item.status),
|
||||||
|
})) as ChannelType[]
|
||||||
|
clearSelection()
|
||||||
|
}
|
||||||
|
|
||||||
//表格数据
|
//表格数据
|
||||||
const tableColumnsOptions = ref(tableColumns)
|
const tableColumnsOptions = ref(tableColumns)
|
||||||
const tableTree = ref([])
|
const tableData = ref([])
|
||||||
|
const tableRef = ref()
|
||||||
|
|
||||||
|
const dialogVisible = ref(false)
|
||||||
|
const dialogTitleType = ref(1)
|
||||||
|
const formData = ref({
|
||||||
|
name: '',
|
||||||
|
channel_fee: null,
|
||||||
|
type: null,
|
||||||
|
api_url: '',
|
||||||
|
api_appid: '',
|
||||||
|
api_key: '',
|
||||||
|
status: 1,
|
||||||
|
})
|
||||||
|
const formItems = ref(formItemsData)
|
||||||
|
const formRules = ref(formRulesData)
|
||||||
|
const optionsMap = ref(optionsMapData)
|
||||||
|
const submitDetail = async () => {
|
||||||
|
dialogVisible.value = false
|
||||||
|
if (dialogTitleType.value === 1) {
|
||||||
|
await createChannel(formData.value)
|
||||||
|
} else {
|
||||||
|
await editChannel(formData.value)
|
||||||
|
}
|
||||||
|
await initData()
|
||||||
|
}
|
||||||
|
|
||||||
|
let currentRow: any = {}
|
||||||
|
|
||||||
|
const handleRowClick = (row: any) => {
|
||||||
|
console.log('handleRowClick', row)
|
||||||
|
currentRow = row
|
||||||
|
}
|
||||||
|
|
||||||
|
const resetFormData = () => {
|
||||||
|
formData.value = {
|
||||||
|
name: '',
|
||||||
|
channel_fee: null,
|
||||||
|
type: null,
|
||||||
|
api_url: '',
|
||||||
|
api_appid: '',
|
||||||
|
api_key: '',
|
||||||
|
status: 1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleAdd = () => {
|
||||||
|
dialogVisible.value = true
|
||||||
|
dialogTitleType.value = 1
|
||||||
|
resetFormData()
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleEdit = () => {
|
||||||
|
if (!currentRow.id) return ElMessage.warning('请先选择要编辑的记录')
|
||||||
|
|
||||||
|
dialogVisible.value = true
|
||||||
|
dialogTitleType.value = 2
|
||||||
|
formData.value = {
|
||||||
|
id: currentRow.id,
|
||||||
|
name: currentRow.name,
|
||||||
|
channel_fee: currentRow.channel_fee,
|
||||||
|
type: currentRow.type,
|
||||||
|
api_url: currentRow.api_url,
|
||||||
|
api_appid: currentRow.api_appid,
|
||||||
|
api_key: currentRow.api_key,
|
||||||
|
status: currentRow.status,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleDelete = () => {
|
||||||
|
console.log('handleDisable')
|
||||||
|
ElMessageBox.confirm('确认删除吗?', '提示', {
|
||||||
|
type: 'warning',
|
||||||
|
confirmButtonText: '确定',
|
||||||
|
cancelButtonText: '取消',
|
||||||
|
})
|
||||||
|
.then(async () => {
|
||||||
|
await delChannel({ id: currentRow.id })
|
||||||
|
await initData()
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
console.log('取消删除')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const clearSelection = () => {
|
||||||
|
currentRow = {}
|
||||||
|
nextTick(() => {
|
||||||
|
tableRef.value?.clearCurrentRow() // 调用子组件方法取消高亮
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
initData()
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.deposit-channel {
|
.deposit-channel {
|
||||||
.bar {
|
.bar {
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
span {
|
span {
|
||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,60 @@
|
||||||
export const tableColumns = [
|
export const tableColumns = [
|
||||||
//序号
|
//序号
|
||||||
{ label: '序号', prop: 'index' },
|
{ label: '序号', type: 'index', width: 60, align: 'center' },
|
||||||
//存款渠道名称
|
//存款渠道名称
|
||||||
{ label: '存款渠道名称', prop: 'depositChannelName' },
|
{ label: '渠道名称', prop: 'name' },
|
||||||
//状态
|
//存款渠道费用
|
||||||
{ label: '状态', slotName: 'status' },
|
{ label: '渠道费用', prop: 'channel_fee' },
|
||||||
|
//存款渠道类型
|
||||||
]
|
{ label: '类型', prop: 'typeStr' },
|
||||||
|
// 接口地址
|
||||||
|
{ label: '接口地址', prop: 'api_url' },
|
||||||
|
// 接口appid
|
||||||
|
{ label: '接口appid', prop: 'api_appid' },
|
||||||
|
{ label: '状态', prop: 'statusStr' },
|
||||||
|
]
|
||||||
|
|
||||||
|
export const formItemsData = [
|
||||||
|
{ label: '渠道名称', prop: 'name', type: 'input', placeholder: '请输入渠道名称' },
|
||||||
|
{
|
||||||
|
label: '渠道费用',
|
||||||
|
prop: 'channel_fee',
|
||||||
|
type: 'number',
|
||||||
|
min: 0,
|
||||||
|
max: 999999,
|
||||||
|
controls: false,
|
||||||
|
placeholder: '请输入渠道费用',
|
||||||
|
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '类型',
|
||||||
|
prop: 'type',
|
||||||
|
type: 'select',
|
||||||
|
placeholder: '请选择类型',
|
||||||
|
}, // 类型:1法币,2数字货币
|
||||||
|
{ label: '接口地址', prop: 'api_url', type: 'input', placeholder: '请输入接口地址' },
|
||||||
|
{ label: '接口appid', prop: 'api_appid', type: 'input', placeholder: '请输入接口appid' },
|
||||||
|
{ label: '接口密钥', prop: 'api_key', type: 'input', placeholder: '请输入接口密钥' },
|
||||||
|
{ label: '状态', prop: 'status', type: 'radio' },
|
||||||
|
]
|
||||||
|
|
||||||
|
export const formRulesData = {
|
||||||
|
name: [{ required: true, message: '请输入渠道名称', trigger: ['change'] }],
|
||||||
|
channel_fee: [{ required: true, message: '请输入渠道费用', trigger: ['change'] }],
|
||||||
|
type: [{ required: true, message: '请选择类型', trigger: ['change'] }],
|
||||||
|
api_url: [{ required: true, message: '请输入接口地址', trigger: ['change'] }],
|
||||||
|
api_appid: [{ required: true, message: '请输入接口appid', trigger: ['change'] }],
|
||||||
|
api_key: [{ required: true, message: '请输入接口密钥', trigger: ['change'] }],
|
||||||
|
status: [{ required: true, message: '请选择状态', trigger: ['change'] }],
|
||||||
|
}
|
||||||
|
|
||||||
|
export const optionsMapData = {
|
||||||
|
type: [
|
||||||
|
{ label: '法币', value: 1 },
|
||||||
|
{ label: '数字货币', value: 2 },
|
||||||
|
],
|
||||||
|
status: [
|
||||||
|
{ label: '启用', value: 1 },
|
||||||
|
{ label: '禁用', value: 2 },
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,36 +1,59 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="rechange-check">
|
<div class="rechange-check">
|
||||||
<!-- 搜索区域:默认把当天 0 点到当前时间写入时间输入框 -->
|
<!-- 搜索区域:默认把当天 0 点到当前时间写入时间输入框 -->
|
||||||
<RechangeSearch :search-form="searchForm" :search-options="searchOptions" @search="handleSearch" @reset="handleReset">
|
<RechangeSearch
|
||||||
<template #button>
|
:search-form="searchForm"
|
||||||
<!-- 审核动作先保留按钮交互,后续可直接接接口 -->
|
:search-options="searchOptions"
|
||||||
<el-button type="danger" plain @click="handleReject">驳回</el-button>
|
@search="handleSearch"
|
||||||
<el-button type="success" @click="handleApprove">通过</el-button>
|
@reset="handleReset"
|
||||||
<el-button type="primary" plain @click="handleExport">导出</el-button>
|
>
|
||||||
</template>
|
<template #button>
|
||||||
</RechangeSearch>
|
<!-- 审核动作先保留按钮交互,后续可直接接接口 -->
|
||||||
|
<el-button type="danger" plain @click="handleReject">驳回</el-button>
|
||||||
|
<el-button type="success" @click="handleApprove">通过</el-button>
|
||||||
|
<el-button type="primary" plain @click="handleExport">导出</el-button>
|
||||||
|
</template>
|
||||||
|
</RechangeSearch>
|
||||||
|
|
||||||
<!-- 列表区域:改为真实接口数据,仍保留勾选列供后续审核动作使用 -->
|
<!-- 列表区域:改为真实接口数据,仍保留勾选列供后续审核动作使用 -->
|
||||||
<div class="table-wrapper">
|
<div class="table-wrapper">
|
||||||
<el-table v-loading="loading" :data="tableData" border height="100%" row-key="id"
|
<el-table
|
||||||
@selection-change="handleSelectionChange">
|
ref="tableRef"
|
||||||
<el-table-column type="selection" width="55" align="center" />
|
v-loading="loading"
|
||||||
|
:data="tableData"
|
||||||
|
border
|
||||||
|
height="100%"
|
||||||
|
row-key="id"
|
||||||
|
@selection-change="handleSelectionChange"
|
||||||
|
>
|
||||||
|
<el-table-column type="selection" width="55" align="center" />
|
||||||
|
|
||||||
<el-table-column label="序号" width="70" align="center">
|
<el-table-column label="序号" width="70" align="center">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
{{ (currentPage - 1) * pageSize + scope.$index + 1 }}
|
{{ (currentPage - 1) * pageSize + scope.$index + 1 }}
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
|
||||||
<el-table-column v-for="column in tableColumns" :key="column.prop" :prop="column.prop" :label="column.label"
|
<el-table-column
|
||||||
:min-width="column.width" :align="column.align || 'center'" show-overflow-tooltip />
|
v-for="column in tableColumns"
|
||||||
</el-table>
|
:key="column.prop"
|
||||||
</div>
|
:prop="column.prop"
|
||||||
|
:label="column.label"
|
||||||
<!-- 分页区域:使用接口返回的 total / current_page / per_page -->
|
:min-width="column.width"
|
||||||
<RechangePagination v-model="currentPage" v-model:pageSizeValue="pageSize" :total="total"
|
:align="column.align || 'center'"
|
||||||
@pagination-change="handlePaginationChange" />
|
show-overflow-tooltip
|
||||||
|
/>
|
||||||
|
</el-table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- 分页区域:使用接口返回的 total / current_page / per_page -->
|
||||||
|
<RechangePagination
|
||||||
|
v-model="currentPage"
|
||||||
|
v-model:pageSizeValue="pageSize"
|
||||||
|
:total="total"
|
||||||
|
@pagination-change="handlePaginationChange"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
|
@ -39,30 +62,31 @@ import { onMounted, ref } from 'vue'
|
||||||
import RechangeSearch from '@/components/common/Search.vue'
|
import RechangeSearch from '@/components/common/Search.vue'
|
||||||
import RechangePagination from '@/components/common/Pagination.vue'
|
import RechangePagination from '@/components/common/Pagination.vue'
|
||||||
import { exportToExcel } from '@/utils/exportToExcel'
|
import { exportToExcel } from '@/utils/exportToExcel'
|
||||||
import { getRechargeCheckListApi } from '@/api/modules/system/rechargeCheck'
|
import { getRechargeCheckListApi, reviewRechargeOrder } from '@/api/modules/capital/rechargeCheck'
|
||||||
import { rechangeCheckSearch, rechangeCheckTableColumns } from './options'
|
import { rechangeCheckSearch, rechangeCheckTableColumns } from './options'
|
||||||
|
import { getRecentSevenDays } from '@/utils/handleTime.ts'
|
||||||
|
|
||||||
// 审核列表单行数据结构:直接对应 `rechargeOrder` 那套返回结果映射。
|
// 审核列表单行数据结构:直接对应 `rechargeOrder` 那套返回结果映射。
|
||||||
interface TableRow {
|
interface TableRow {
|
||||||
id: number
|
id: number
|
||||||
orderNo: string
|
orderNo: string
|
||||||
userName: string
|
userName: string
|
||||||
currency: string
|
currency: string
|
||||||
amount: string
|
amount: string
|
||||||
realCurrency: string
|
realCurrency: string
|
||||||
realAmount: string
|
realAmount: string
|
||||||
rate: string
|
rate: string
|
||||||
status: string
|
status: string
|
||||||
statusText: string
|
statusText: string
|
||||||
rechangeTime: string
|
rechangeTime: string
|
||||||
}
|
}
|
||||||
|
|
||||||
// 搜索表单结构:与审核接口的查询参数一一对应。
|
// 搜索表单结构:与审核接口的查询参数一一对应。
|
||||||
interface SearchFormData {
|
interface SearchFormData {
|
||||||
orderNo: string
|
orderNo: string
|
||||||
userName: string
|
userName: string
|
||||||
startTime: string
|
startTime: string
|
||||||
endTime: string
|
endTime: string
|
||||||
}
|
}
|
||||||
|
|
||||||
// 搜索配置和表格配置。
|
// 搜索配置和表格配置。
|
||||||
|
|
@ -79,194 +103,191 @@ const total = ref(0)
|
||||||
const currentPage = ref(1)
|
const currentPage = ref(1)
|
||||||
const pageSize = ref(10)
|
const pageSize = ref(10)
|
||||||
|
|
||||||
// 时间格式化工具:用于生成接口必传的开始/结束时间默认值。
|
const initTime = getRecentSevenDays()
|
||||||
const padZero = (value: number) => String(value).padStart(2, '0')
|
|
||||||
|
|
||||||
const formatDateTime = (date: Date) => {
|
|
||||||
const year = date.getFullYear()
|
|
||||||
const month = padZero(date.getMonth() + 1)
|
|
||||||
const day = padZero(date.getDate())
|
|
||||||
const hours = padZero(date.getHours())
|
|
||||||
const minutes = padZero(date.getMinutes())
|
|
||||||
const seconds = padZero(date.getSeconds())
|
|
||||||
|
|
||||||
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`
|
|
||||||
}
|
|
||||||
|
|
||||||
const getTodayStartTime = () => {
|
|
||||||
const now = new Date()
|
|
||||||
now.setHours(0, 0, 0, 0)
|
|
||||||
return formatDateTime(now)
|
|
||||||
}
|
|
||||||
|
|
||||||
const getCurrentTime = () => formatDateTime(new Date())
|
|
||||||
|
|
||||||
// 默认搜索表单:开始时间固定为当天 0 点,结束时间固定为当前时间,并直接显示在输入框里。
|
// 默认搜索表单:开始时间固定为当天 0 点,结束时间固定为当前时间,并直接显示在输入框里。
|
||||||
const createDefaultSearchForm = (): SearchFormData => ({
|
const createDefaultSearchForm = (): SearchFormData => ({
|
||||||
orderNo: '',
|
orderNo: '',
|
||||||
userName: '',
|
userName: '',
|
||||||
startTime: getTodayStartTime(),
|
startTime: initTime.start,
|
||||||
endTime: getCurrentTime(),
|
endTime: initTime.end,
|
||||||
})
|
})
|
||||||
|
|
||||||
const searchForm = ref<SearchFormData>(createDefaultSearchForm())
|
const searchForm = ref<SearchFormData>(createDefaultSearchForm())
|
||||||
|
|
||||||
// 充值状态映射:与充值订单列表保持一致。
|
// 充值状态映射:与充值订单列表保持一致。
|
||||||
const getRechargeStatusText = (status: string | number | null | undefined) => {
|
const getRechargeStatusText = (status: string | number | null | undefined) => {
|
||||||
const statusMap: Record<string, string> = {
|
const statusMap: Record<string, string> = {
|
||||||
'1': '未审核',
|
'1': '未审核',
|
||||||
'2': '未付款',
|
'2': '未付款',
|
||||||
'3': '已付款',
|
'3': '已付款',
|
||||||
'4': '驳回',
|
'4': '驳回',
|
||||||
}
|
}
|
||||||
|
|
||||||
return statusMap[String(status ?? '')] || '--'
|
return statusMap[String(status ?? '')] || '--'
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取审核列表:page / page_size / start_time / end_time 必传,其余空值统一传 null。
|
// 获取审核列表:page / page_size / start_time / end_time 必传,其余空值统一传 null。
|
||||||
const getList = async () => {
|
const getList = async () => {
|
||||||
loading.value = true
|
loading.value = true
|
||||||
selectedRows.value = []
|
selectedRows.value = []
|
||||||
|
|
||||||
const params = {
|
const params = {
|
||||||
page: currentPage.value,
|
page: currentPage.value,
|
||||||
page_size: pageSize.value,
|
page_size: pageSize.value,
|
||||||
trade_id: searchForm.value.orderNo || null,
|
trade_id: searchForm.value.orderNo || null,
|
||||||
start_time: searchForm.value.startTime || getTodayStartTime(),
|
start_time: searchForm.value.startTime || initTime.start,
|
||||||
end_time: searchForm.value.endTime || getCurrentTime(),
|
end_time: searchForm.value.endTime || initTime.end,
|
||||||
user_name: searchForm.value.userName || null,
|
user_name: searchForm.value.userName || null,
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const data: any = await getRechargeCheckListApi(params)
|
const data: any = await getRechargeCheckListApi(params)
|
||||||
const list = Array.isArray(data?.data) ? data.data : []
|
const list = Array.isArray(data?.data) ? data.data : []
|
||||||
|
|
||||||
tableData.value = list.map((item: any, index: number) => ({
|
tableData.value = list.map((item: any, index: number) => ({
|
||||||
id: Number(item.id ?? index + 1),
|
id: Number(item.id ?? index + 1),
|
||||||
orderNo: String(item.trade_id ?? '--'),
|
orderNo: String(item.trade_id ?? '--'),
|
||||||
userName: item.user?.username ?? '--',
|
userName: item.user?.username ?? '--',
|
||||||
currency: item.recharge_currency?.symbol ?? '--',
|
currency: item.recharge_currency?.symbol ?? '--',
|
||||||
amount: String(item.recharge_amount ?? '--'),
|
amount: String(item.recharge_amount ?? '--'),
|
||||||
realCurrency: item.real_currency?.symbol ?? '--',
|
realCurrency: item.real_currency?.symbol ?? '--',
|
||||||
realAmount: String(item.real_amount ?? '--'),
|
realAmount: String(item.real_amount ?? '--'),
|
||||||
rate: String(item.rate ?? '--'),
|
rate: String(item.rate ?? '--'),
|
||||||
status: String(item.status ?? ''),
|
status: String(item.status ?? ''),
|
||||||
statusText: getRechargeStatusText(item.status),
|
statusText: getRechargeStatusText(item.status),
|
||||||
rechangeTime: item.created_at ?? '--',
|
rechangeTime: item.created_at ?? '--',
|
||||||
}))
|
}))
|
||||||
|
|
||||||
total.value = Number(data?.total ?? list.length)
|
total.value = Number(data?.total ?? list.length)
|
||||||
currentPage.value = Number(data?.current_page ?? currentPage.value)
|
currentPage.value = Number(data?.current_page ?? currentPage.value)
|
||||||
pageSize.value = Number(data?.per_page ?? pageSize.value)
|
pageSize.value = Number(data?.per_page ?? pageSize.value)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
tableData.value = []
|
tableData.value = []
|
||||||
total.value = 0
|
total.value = 0
|
||||||
console.error('获取充值审核列表失败', error)
|
console.error('获取充值审核列表失败', error)
|
||||||
} finally {
|
} finally {
|
||||||
loading.value = false
|
loading.value = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 页面初始化时加载一次真实列表。
|
// 页面初始化时加载一次真实列表。
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getList()
|
getList()
|
||||||
})
|
})
|
||||||
|
|
||||||
// 搜索:回到第一页再重新请求。
|
// 搜索:回到第一页再重新请求。
|
||||||
const handleSearch = () => {
|
const handleSearch = () => {
|
||||||
currentPage.value = 1
|
currentPage.value = 1
|
||||||
getList()
|
getList()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 重置:恢复默认时间范围和空搜索条件。
|
// 重置:恢复默认时间范围和空搜索条件。
|
||||||
const handleReset = () => {
|
const handleReset = () => {
|
||||||
searchForm.value = createDefaultSearchForm()
|
searchForm.value = createDefaultSearchForm()
|
||||||
currentPage.value = 1
|
currentPage.value = 1
|
||||||
pageSize.value = 10
|
pageSize.value = 10
|
||||||
getList()
|
getList()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const tableRef = ref()
|
||||||
// 表格勾选变化。
|
// 表格勾选变化。
|
||||||
const handleSelectionChange = (rows: TableRow[]) => {
|
const handleSelectionChange = (rows: TableRow[]) => {
|
||||||
|
if (rows.length > 1) {
|
||||||
|
// 超过1个时,移除最早选中的那个(保留最后一个)
|
||||||
|
const lastRow = rows[rows.length - 1]
|
||||||
|
// 先清除所有选择
|
||||||
|
tableRef.value?.clearSelection()
|
||||||
|
// 再单独选中最后点击的这行
|
||||||
|
tableRef.value?.toggleRowSelection(lastRow, true)
|
||||||
|
selectedRows.value = [lastRow]
|
||||||
|
} else {
|
||||||
selectedRows.value = rows
|
selectedRows.value = rows
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 审核通过:当前保留前端提示,等待后续接接口。
|
// 审核通过:当前保留前端提示,等待后续接接口。
|
||||||
const handleApprove = () => {
|
const handleApprove = () => {
|
||||||
if (!selectedRows.value.length) {
|
if (!selectedRows.value.length) {
|
||||||
ElMessage.warning('请先选择要通过的记录')
|
ElMessage.warning('请先选择要通过的记录')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ElMessage.success('审核通过接口待接入')
|
console.log(selectedRows.value)
|
||||||
|
reviewRechargeOrder({ id: selectedRows.value[0].id, status: '3' })
|
||||||
|
ElMessage.success('审核通过')
|
||||||
|
getList()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 审核驳回:当前保留前端提示,等待后续接接口。
|
// 审核驳回:当前保留前端提示,等待后续接接口。
|
||||||
const handleReject = () => {
|
const handleReject = () => {
|
||||||
if (!selectedRows.value.length) {
|
if (!selectedRows.value.length) {
|
||||||
ElMessage.warning('请先选择要驳回的记录')
|
ElMessage.warning('请先选择要驳回的记录')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ElMessage.success('审核驳回接口待接入')
|
//充值状态:1未审核,2未付款,3已付款,4驳回
|
||||||
|
reviewRechargeOrder({ id: selectedRows.value[0].id, status: '4' })
|
||||||
|
ElMessage.success('审核驳回')
|
||||||
|
getList()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 导出:先导出当前页接口数据,后续如需全量导出可切成独立导出接口。
|
// 导出:先导出当前页接口数据,后续如需全量导出可切成独立导出接口。
|
||||||
const handleExport = async () => {
|
const handleExport = async () => {
|
||||||
await exportToExcel({
|
await exportToExcel({
|
||||||
tableData: tableData.value,
|
tableData: tableData.value,
|
||||||
columns: tableColumns.value,
|
columns: tableColumns.value,
|
||||||
title: '导出充值审核',
|
title: '导出充值审核',
|
||||||
defaultFileNamePrefix: '充值审核',
|
defaultFileNamePrefix: '充值审核',
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 分页变化:更新页码和每页条数后重新请求数据。
|
// 分页变化:更新页码和每页条数后重新请求数据。
|
||||||
const handlePaginationChange = (page: { currentPage: number; pageSize: number }) => {
|
const handlePaginationChange = (page: { currentPage: number; pageSize: number }) => {
|
||||||
currentPage.value = page.currentPage
|
currentPage.value = page.currentPage
|
||||||
pageSize.value = page.pageSize
|
pageSize.value = page.pageSize
|
||||||
getList()
|
getList()
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.rechange-check {
|
.rechange-check {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
padding-bottom: 70px;
|
padding-bottom: 70px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
|
||||||
// 覆盖公共搜索组件默认的弹性拉伸,让当前页搜索项宽度按配置展示。
|
// 覆盖公共搜索组件默认的弹性拉伸,让当前页搜索项宽度按配置展示。
|
||||||
:deep(.search-container .el-form) {
|
:deep(.search-container .el-form) {
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.search-container .el-form-item) {
|
:deep(.search-container .el-form-item) {
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
margin-bottom: 8px;
|
margin-bottom: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.search-container .el-input),
|
:deep(.search-container .el-input),
|
||||||
:deep(.search-container .el-select),
|
:deep(.search-container .el-select),
|
||||||
:deep(.search-container .el-date-editor) {
|
:deep(.search-container .el-date-editor) {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 表格区域接管剩余空间,并确保横向也能撑满页面。
|
// 表格区域接管剩余空间,并确保横向也能撑满页面。
|
||||||
.table-wrapper {
|
.table-wrapper {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.el-table),
|
:deep(.el-table),
|
||||||
:deep(.el-table__inner-wrapper),
|
:deep(.el-table__inner-wrapper),
|
||||||
:deep(.el-scrollbar) {
|
:deep(.el-scrollbar) {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,37 +1,39 @@
|
||||||
// 搜索区域配置:按充值审核接口的实际查询参数保留订单号、用户名、开始时间、结束时间。
|
// 搜索区域配置:按充值审核接口的实际查询参数保留订单号、用户名、开始时间、结束时间。
|
||||||
export const rechangeCheckSearch = [
|
export const rechangeCheckSearch = [
|
||||||
{
|
{
|
||||||
prop: 'orderNo',
|
prop: 'orderNo',
|
||||||
label: '订单号',
|
label: '订单号',
|
||||||
type: 'input' as const,
|
type: 'input' as const,
|
||||||
placeholder: '请输入流水号',
|
placeholder: '请输入流水号',
|
||||||
width: '220px',
|
width: '220px',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
prop: 'userName',
|
prop: 'userName',
|
||||||
label: '用户名称',
|
label: '用户名称',
|
||||||
type: 'input' as const,
|
type: 'input' as const,
|
||||||
placeholder: '请输入用户名',
|
placeholder: '请输入用户名',
|
||||||
width: '200px',
|
width: '200px',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
prop: 'startTime',
|
prop: 'startTime',
|
||||||
label: '开始时间',
|
label: '开始时间',
|
||||||
type: 'date' as const,
|
type: 'date' as const,
|
||||||
dateType: 'datetime' as const,
|
dateType: 'datetime' as const,
|
||||||
valueFormat: 'YYYY-MM-DD HH:mm:ss',
|
valueFormat: 'YYYY-MM-DD HH:mm:ss',
|
||||||
placeholder: '请选择开始时间',
|
placeholder: '请选择开始时间',
|
||||||
width: '220px',
|
clearable: false,
|
||||||
},
|
width: '260px',
|
||||||
{
|
},
|
||||||
prop: 'endTime',
|
{
|
||||||
label: '结束时间',
|
prop: 'endTime',
|
||||||
type: 'date' as const,
|
label: '结束时间',
|
||||||
dateType: 'datetime' as const,
|
type: 'date' as const,
|
||||||
valueFormat: 'YYYY-MM-DD HH:mm:ss',
|
dateType: 'datetime' as const,
|
||||||
placeholder: '请选择结束时间',
|
valueFormat: 'YYYY-MM-DD HH:mm:ss',
|
||||||
width: '220px',
|
placeholder: '请选择结束时间',
|
||||||
},
|
clearable: false,
|
||||||
|
width: '260px',
|
||||||
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
// 表格列配置:返回数据与 `rechargeOrder` 一致,因此按同一份结构展示。
|
// 表格列配置:返回数据与 `rechargeOrder` 一致,因此按同一份结构展示。
|
||||||
|
|
|
||||||
|
|
@ -79,7 +79,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, onMounted, nextTick } from 'vue'
|
import { ref, onMounted } from 'vue'
|
||||||
import {
|
import {
|
||||||
getFeeSettingList,
|
getFeeSettingList,
|
||||||
getFeeSettingDetail,
|
getFeeSettingDetail,
|
||||||
|
|
@ -90,8 +90,6 @@ import {
|
||||||
import Form from '@/components/common/Form.vue'
|
import Form from '@/components/common/Form.vue'
|
||||||
import { formDataList, formRulesList } from './option.ts'
|
import { formDataList, formRulesList } from './option.ts'
|
||||||
|
|
||||||
const title = ref('手续费模板')
|
|
||||||
const buttons = ref([{ label: '新增', type: 'primary' as const, key: 'add' }])
|
|
||||||
|
|
||||||
const dialogVisible = ref(false)
|
const dialogVisible = ref(false)
|
||||||
const dialogTitleType = ref(1)
|
const dialogTitleType = ref(1)
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,38 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="order-rechange-page">
|
<div class="order-rechange-page">
|
||||||
<!-- 搜索区域:按接口参数保留订单号、用户名称、状态、开始/结束时间 -->
|
<!-- 搜索区域:按接口参数保留订单号、用户名称、状态、开始/结束时间 -->
|
||||||
<OrderRechangeSearch :search-form="searchForm" :search-options="searchOptions" @search="handleSearch"
|
<OrderRechangeSearch
|
||||||
@reset="handleReset" />
|
:search-form="searchForm"
|
||||||
|
:search-options="searchOptions"
|
||||||
|
@search="handleSearch"
|
||||||
|
@reset="handleReset"
|
||||||
|
></OrderRechangeSearch>
|
||||||
|
|
||||||
<!-- 列表区域:改为真实接口数据,保留原有表格结构 -->
|
<!-- 列表区域:改为真实接口数据,保留原有表格结构 -->
|
||||||
<OrderRechangeTable :table-data="tableTree" :columns="tableColumnsOptions" :highlight-current-row="false" />
|
<OrderRechangeTable
|
||||||
|
:table-data="tableTree"
|
||||||
|
:columns="tableColumnsOptions"
|
||||||
|
:highlight-current-row="false"
|
||||||
|
>
|
||||||
|
<!-- 操作列插槽 -->
|
||||||
|
<template #operation="{ row }">
|
||||||
|
<el-button type="primary" :disabled="row.status !== '1'" @click="handleAudit(row, 3)"
|
||||||
|
>审核通过</el-button
|
||||||
|
>
|
||||||
|
<el-button type="danger" :disabled="row.status !== '1'" @click="handleAudit(row, 4)"
|
||||||
|
>审核驳回</el-button
|
||||||
|
>
|
||||||
|
</template>
|
||||||
|
</OrderRechangeTable>
|
||||||
|
|
||||||
<!-- 分页区域:使用接口返回的 total / current_page / per_page -->
|
<!-- 分页区域:使用接口返回的 total / current_page / per_page -->
|
||||||
<OrderRechangePagination v-model="currentPage" v-model:pageSizeValue="pageSize" :total="total"
|
<OrderRechangePagination
|
||||||
@pagination-change="handlePaginationChange" />
|
v-model="currentPage"
|
||||||
</div>
|
v-model:pageSizeValue="pageSize"
|
||||||
|
:total="total"
|
||||||
|
@pagination-change="handlePaginationChange"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
|
@ -18,29 +40,32 @@ import { onMounted, ref } from 'vue'
|
||||||
import OrderRechangeSearch from '@/components/common/Search.vue'
|
import OrderRechangeSearch from '@/components/common/Search.vue'
|
||||||
import OrderRechangeTable from '@/components/common/Table.vue'
|
import OrderRechangeTable from '@/components/common/Table.vue'
|
||||||
import OrderRechangePagination from '@/components/common/Pagination.vue'
|
import OrderRechangePagination from '@/components/common/Pagination.vue'
|
||||||
import { getRechargeOrderListApi } from '@/api/modules/system/rechargeOrder'
|
import { getRechargeOrderListApi, reviewRechargeOrder } from '@/api/modules/order/rechange.ts'
|
||||||
import { search, tableColumns } from './options'
|
import { search, tableColumns } from './options'
|
||||||
|
import { getRecentSevenDays } from '@/utils/handleTime.ts'
|
||||||
|
|
||||||
// 充值订单数据结构:只保留页面展示所需字段,接口原始字段在请求后统一映射。
|
// 充值订单数据结构:只保留页面展示所需字段,接口原始字段在请求后统一映射。
|
||||||
interface RechangeOrderItem {
|
interface RechangeOrderItem {
|
||||||
id: number
|
id: number
|
||||||
orderNo: string
|
orderNo: string
|
||||||
userName: string
|
userName: string
|
||||||
currency: string
|
currency: string
|
||||||
amount: string
|
amount: string
|
||||||
status: string
|
status: string
|
||||||
statusText: string
|
statusText: string
|
||||||
rechangeTime: string
|
rechangeTime: string
|
||||||
rechangeAccount: string
|
rechangeAccount: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const initTime = getRecentSevenDays('YYYY-MM-DD')
|
||||||
|
|
||||||
// 搜索表单结构:与接口查询参数一一对应,页面字段名保持可读性。
|
// 搜索表单结构:与接口查询参数一一对应,页面字段名保持可读性。
|
||||||
interface SearchFormData {
|
interface SearchFormData {
|
||||||
orderNo: string
|
trade_id: string
|
||||||
userName: string
|
user_name: string
|
||||||
status: string
|
status: string
|
||||||
startTime: string
|
start_time: string
|
||||||
endTime: string
|
end_time: string
|
||||||
}
|
}
|
||||||
|
|
||||||
// 搜索项配置。
|
// 搜索项配置。
|
||||||
|
|
@ -48,11 +73,11 @@ const searchOptions = ref(search)
|
||||||
|
|
||||||
// 搜索表单:由公共 Search 组件双向绑定。
|
// 搜索表单:由公共 Search 组件双向绑定。
|
||||||
const createDefaultSearchForm = (): SearchFormData => ({
|
const createDefaultSearchForm = (): SearchFormData => ({
|
||||||
orderNo: '',
|
trade_id: '',
|
||||||
userName: '',
|
user_name: '',
|
||||||
status: '',
|
status: '',
|
||||||
startTime: '',
|
start_time: initTime.start,
|
||||||
endTime: '',
|
end_time: initTime.end,
|
||||||
})
|
})
|
||||||
|
|
||||||
const searchForm = ref<SearchFormData>(createDefaultSearchForm())
|
const searchForm = ref<SearchFormData>(createDefaultSearchForm())
|
||||||
|
|
@ -68,133 +93,125 @@ const total = ref(0)
|
||||||
|
|
||||||
// 充值状态映射:对齐接口文档中的 1/2/3/4 定义。
|
// 充值状态映射:对齐接口文档中的 1/2/3/4 定义。
|
||||||
const getRechargeStatusText = (status: string | number | null | undefined) => {
|
const getRechargeStatusText = (status: string | number | null | undefined) => {
|
||||||
const statusMap: Record<string, string> = {
|
const statusMap: Record<string, string> = {
|
||||||
'1': '未审核',
|
'1': '未审核',
|
||||||
'2': '未付款',
|
'2': '未付款',
|
||||||
'3': '已付款',
|
'3': '已付款',
|
||||||
'4': '驳回',
|
'4': '驳回',
|
||||||
}
|
}
|
||||||
|
|
||||||
return statusMap[String(status ?? '')] || '--'
|
return statusMap[String(status ?? '')] || '--'
|
||||||
}
|
}
|
||||||
|
|
||||||
// 格式化日期时间:用于生成接口需要的 `YYYY-MM-DD HH:mm:ss`。
|
|
||||||
const padZero = (value: number) => String(value).padStart(2, '0')
|
|
||||||
|
|
||||||
const formatDateTime = (date: Date) => {
|
|
||||||
const year = date.getFullYear()
|
|
||||||
const month = padZero(date.getMonth() + 1)
|
|
||||||
const day = padZero(date.getDate())
|
|
||||||
const hours = padZero(date.getHours())
|
|
||||||
const minutes = padZero(date.getMinutes())
|
|
||||||
const seconds = padZero(date.getSeconds())
|
|
||||||
|
|
||||||
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`
|
|
||||||
}
|
|
||||||
|
|
||||||
const getTodayStartTime = () => {
|
|
||||||
const now = new Date()
|
|
||||||
now.setHours(0, 0, 0, 0)
|
|
||||||
return formatDateTime(now)
|
|
||||||
}
|
|
||||||
|
|
||||||
const getCurrentTime = () => formatDateTime(new Date())
|
|
||||||
|
|
||||||
// 获取充值订单列表:把接口返回字段统一映射成页面表格结构。
|
// 获取充值订单列表:把接口返回字段统一映射成页面表格结构。
|
||||||
const getRechargeOrderList = async () => {
|
const getRechargeOrderList = async () => {
|
||||||
const params = {
|
const params = {
|
||||||
page: currentPage.value,
|
page: currentPage.value,
|
||||||
page_size: pageSize.value,
|
page_size: pageSize.value,
|
||||||
trade_id: searchForm.value.orderNo || null,
|
trade_id: searchForm.value.trade_id || null,
|
||||||
start_time: searchForm.value.startTime ? `${searchForm.value.startTime} 00:00:00` : getTodayStartTime(),
|
start_time: searchForm.value.start_time
|
||||||
end_time: searchForm.value.endTime ? `${searchForm.value.endTime} 23:59:59` : getCurrentTime(),
|
? `${searchForm.value.start_time} 00:00:00`
|
||||||
user_name: searchForm.value.userName || null,
|
: initTime.start,
|
||||||
status: searchForm.value.status || null,
|
end_time: searchForm.value.end_time ? `${searchForm.value.end_time} 23:59:59` : initTime.end,
|
||||||
}
|
user_name: searchForm.value.user_name || null,
|
||||||
|
status: searchForm.value.status || null,
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const data: any = await getRechargeOrderListApi(params)
|
const data: any = await getRechargeOrderListApi(params)
|
||||||
const list = Array.isArray(data?.data) ? data.data : []
|
const list = Array.isArray(data?.data) ? data.data : []
|
||||||
|
|
||||||
tableTree.value = list.map((item: any, index: number) => ({
|
tableTree.value = list.map((item: any, index: number) => ({
|
||||||
id: Number(item.id ?? index + 1),
|
id: Number(item.id ?? index + 1),
|
||||||
// 订单号:接口返回字段为 trade_id
|
// 订单号:接口返回字段为 trade_id
|
||||||
orderNo: String(item.trade_id ?? '--'),
|
orderNo: String(item.trade_id ?? '--'),
|
||||||
// 用户名:用于后续可能的页面扩展,当前取 user.username
|
// 用户名:用于后续可能的页面扩展,当前取 user.username
|
||||||
userName: item.user?.username ?? '--',
|
userName: item.user?.username ?? '--',
|
||||||
// 充值币种:根据返回结构取 recharge_currency.symbol
|
// 充值币种:根据返回结构取 recharge_currency.symbol
|
||||||
currency: item.recharge_currency?.symbol ?? '--',
|
currency: item.recharge_currency?.symbol ?? '--',
|
||||||
// 金额:根据返回结构取 recharge_amount
|
// 金额:根据返回结构取 recharge_amount
|
||||||
amount: String(item.recharge_amount ?? '--'),
|
amount: String(item.recharge_amount ?? '--'),
|
||||||
status: String(item.status ?? ''),
|
status: String(item.status ?? ''),
|
||||||
statusText: getRechargeStatusText(item.status),
|
statusText: getRechargeStatusText(item.status),
|
||||||
// 充值时间:根据返回结构取 created_at
|
// 充值时间:根据返回结构取 created_at
|
||||||
rechangeTime: item.created_at ?? '--',
|
rechangeTime: item.created_at ?? '--',
|
||||||
// 充值账号:当前返回里最接近账号标识的是 user.username
|
// 充值账号:当前返回里最接近账号标识的是 user.username
|
||||||
rechangeAccount: item.user?.username ?? '--',
|
rechangeAccount: item.user?.username ?? '--',
|
||||||
}))
|
}))
|
||||||
|
|
||||||
total.value = Number(data?.total ?? list.length)
|
total.value = Number(data?.total ?? list.length)
|
||||||
currentPage.value = Number(data?.current_page ?? currentPage.value)
|
currentPage.value = Number(data?.current_page ?? currentPage.value)
|
||||||
pageSize.value = Number(data?.per_page ?? pageSize.value)
|
pageSize.value = Number(data?.per_page ?? pageSize.value)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
tableTree.value = []
|
tableTree.value = []
|
||||||
total.value = 0
|
total.value = 0
|
||||||
console.error('获取充值订单列表失败', error)
|
console.error('获取充值订单列表失败', error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 页面加载后拉取首屏数据。
|
// 页面加载后拉取首屏数据。
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getRechargeOrderList()
|
getRechargeOrderList()
|
||||||
})
|
})
|
||||||
|
|
||||||
// 搜索:切回第一页后重新请求列表。
|
// 搜索:切回第一页后重新请求列表。
|
||||||
const handleSearch = () => {
|
const handleSearch = () => {
|
||||||
currentPage.value = 1
|
currentPage.value = 1
|
||||||
getRechargeOrderList()
|
getRechargeOrderList()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 重置:恢复默认搜索条件并重新请求列表。
|
// 重置:恢复默认搜索条件并重新请求列表。
|
||||||
const handleReset = () => {
|
const handleReset = () => {
|
||||||
searchForm.value = createDefaultSearchForm()
|
searchForm.value = createDefaultSearchForm()
|
||||||
currentPage.value = 1
|
currentPage.value = 1
|
||||||
pageSize.value = 10
|
pageSize.value = 10
|
||||||
getRechargeOrderList()
|
getRechargeOrderList()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 分页切换:同步页码和每页条数后重新请求。
|
// 分页切换:同步页码和每页条数后重新请求。
|
||||||
const handlePaginationChange = (page: { currentPage: number; pageSize: number }) => {
|
const handlePaginationChange = (page: { currentPage: number; pageSize: number }) => {
|
||||||
currentPage.value = page.currentPage
|
currentPage.value = page.currentPage
|
||||||
pageSize.value = page.pageSize
|
pageSize.value = page.pageSize
|
||||||
getRechargeOrderList()
|
getRechargeOrderList()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 审核通过:调用接口修改状态为 3 已付款。
|
||||||
|
const handleAudit = async (row: RechangeOrderItem, status: number) => {
|
||||||
|
try {
|
||||||
|
await reviewRechargeOrder({ id: row.id, status: status })
|
||||||
|
ElMessage.success('审核通过')
|
||||||
|
await getRechargeOrderList()
|
||||||
|
} catch (error) {
|
||||||
|
ElMessage.error('审核失败')
|
||||||
|
console.error('审核失败', error)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.order-rechange-page {
|
.order-rechange-page {
|
||||||
min-height: 100%;
|
min-height: 100%;
|
||||||
|
|
||||||
// 覆盖公共搜索组件的拉伸行为,让输入框尺寸更接近设计图。
|
// 覆盖公共搜索组件的拉伸行为,让输入框尺寸更接近设计图。
|
||||||
:deep(.search-container .el-form) {
|
:deep(.search-container .el-form) {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.search-container .el-form-item) {
|
:deep(.search-container .el-form-item) {
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
margin-bottom: 8px;
|
margin-bottom: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.search-container .el-input),
|
:deep(.search-container .el-input),
|
||||||
:deep(.search-container .el-select),
|
:deep(.search-container .el-select),
|
||||||
:deep(.search-container .el-date-editor) {
|
:deep(.search-container .el-date-editor) {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.table-container) {
|
:deep(.table-container) {
|
||||||
height: calc(100vh - 220px);
|
height: calc(100vh - 220px);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,60 +1,60 @@
|
||||||
// 充值订单搜索项:按接口参数保留订单号、用户名称、状态、结束时间、开始时间。
|
// 充值订单搜索项:按接口参数保留订单号、用户名称、状态、结束时间、开始时间。
|
||||||
export const search = [
|
export const search = [
|
||||||
{
|
{
|
||||||
prop: 'orderNo',
|
prop: 'trade_id',
|
||||||
label: '订单号',
|
label: '订单号',
|
||||||
type: 'input' as const,
|
type: 'input' as const,
|
||||||
placeholder: '请输入流水号',
|
placeholder: '请输入流水号',
|
||||||
width: '210px',
|
width: '210px',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
prop: 'userName',
|
prop: 'user_name',
|
||||||
label: '用户名称',
|
label: '用户名称',
|
||||||
type: 'input' as const,
|
type: 'input' as const,
|
||||||
placeholder: '请输入用户名',
|
placeholder: '请输入用户名',
|
||||||
width: '190px',
|
width: '190px',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
prop: 'status',
|
prop: 'status',
|
||||||
label: '状态',
|
label: '状态',
|
||||||
type: 'select' as const,
|
type: 'select' as const,
|
||||||
placeholder: '请选择状态',
|
placeholder: '请选择状态',
|
||||||
width: '140px',
|
width: '140px',
|
||||||
options: [
|
options: [
|
||||||
{ label: '未审核', value: '1' },
|
{ label: '未审核', value: '1' },
|
||||||
{ label: '未付款', value: '2' },
|
{ label: '未付款', value: '2' },
|
||||||
{ label: '已付款', value: '3' },
|
{ label: '已付款', value: '3' },
|
||||||
{ label: '驳回', value: '4' },
|
{ label: '驳回', value: '4' },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
prop: 'startTime',
|
prop: 'start_time',
|
||||||
label: '开始时间',
|
label: '开始时间',
|
||||||
type: 'date' as const,
|
type: 'date' as const,
|
||||||
dateType: 'date' as const,
|
dateType: 'date' as const,
|
||||||
valueFormat: 'YYYY-MM-DD',
|
valueFormat: 'YYYY-MM-DD',
|
||||||
placeholder: '请选择开始时间',
|
placeholder: '请选择开始时间',
|
||||||
width: '150px',
|
width: '260px',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
prop: 'endTime',
|
prop: 'end_time',
|
||||||
label: '结束时间',
|
label: '结束时间',
|
||||||
type: 'date' as const,
|
type: 'date' as const,
|
||||||
dateType: 'date' as const,
|
dateType: 'date' as const,
|
||||||
valueFormat: 'YYYY-MM-DD',
|
valueFormat: 'YYYY-MM-DD',
|
||||||
placeholder: '请选择结束时间',
|
placeholder: '请选择结束时间',
|
||||||
width: '150px',
|
width: '260px',
|
||||||
},
|
},
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
||||||
// 充值订单表格列:对应接口数据映射后的列表字段。
|
// 充值订单表格列:对应接口数据映射后的列表字段。
|
||||||
export const tableColumns = [
|
export const tableColumns = [
|
||||||
{ prop: 'orderNo', label: '订单号', align: 'center' as const },
|
{ prop: 'orderNo', label: '订单号', align: 'center' as const },
|
||||||
{ prop: 'currency', label: '充值币种', align: 'center' as const },
|
{ prop: 'currency', label: '充值币种', align: 'center' as const },
|
||||||
{ prop: 'amount', label: '金额', align: 'center' as const },
|
{ prop: 'amount', label: '金额', align: 'center' as const },
|
||||||
{ prop: 'statusText', label: '状态', align: 'center' as const },
|
{ prop: 'statusText', label: '状态', align: 'center' as const },
|
||||||
{ prop: 'rechangeTime', label: '充值时间', align: 'center' as const },
|
{ prop: 'rechangeTime', label: '充值时间', align: 'center' as const },
|
||||||
{ prop: 'rechangeAccount', label: '充值账号', align: 'center' as const },
|
{ prop: 'rechangeAccount', label: '充值账号', align: 'center' as const },
|
||||||
|
{ label: '操作', width: '240px', align: 'center' as const, slotName: 'operation' },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue