3 changed files with 1035 additions and 8 deletions
-
19src/api/cash/financialAccount.js
-
510src/views/moneyManage/financialAccount/cashFlow.vue
-
510src/views/moneyManage/financialAccount/performanceAttribution.vue
@ -0,0 +1,19 @@ |
|||
import http from '@/util/http.js' |
|||
|
|||
//查询资金流水
|
|||
export const Moneyfunds = (data) => { |
|||
return http({ |
|||
method: 'POST', |
|||
url: '/Money/funds', |
|||
data |
|||
}) |
|||
} |
|||
|
|||
// 新增线上退款
|
|||
export const refundOnline = (data) => { |
|||
return http({ |
|||
method: 'POST', |
|||
url: '/Money/addOnline', |
|||
data |
|||
}) |
|||
} |
|||
@ -1,5 +1,509 @@ |
|||
<script setup> |
|||
import { ref, reactive, onMounted } from 'vue' |
|||
import { ElMessage, ElMessageBox } from 'element-plus' |
|||
import request from '@/util/http.js' |
|||
import dayjs from 'dayjs' |
|||
import { useI18n } from 'vue-i18n' |
|||
import { Moneyfunds,refundOnline } from '@/api/cash/financialAccount.js' |
|||
|
|||
const { t } = useI18n() |
|||
|
|||
const paytypeList = [ |
|||
t('cash.payMethods.stripe'), |
|||
t('cash.payMethods.paymentAsia'), |
|||
t('cash.payMethods.ipay88'), |
|||
t('cash.payMethods.bankTransfer'), |
|||
t('cash.payMethods.card'), |
|||
t('cash.payMethods.cash'), |
|||
t('cash.payMethods.check'), |
|||
t('cash.payMethods.grabpay'), |
|||
t('cash.payMethods.nets'), |
|||
t('cash.payMethods.transfer'), |
|||
t('cash.payMethods.paypal'), |
|||
] |
|||
|
|||
const payPlatformOptions = ref([...paytypeList]) |
|||
|
|||
const statusOptions = [ |
|||
{ label: '已到账', value: 4 }, |
|||
{ label: '已退款', value: 6 } |
|||
] |
|||
|
|||
// 地区树 |
|||
const marketOptions = ref([]) |
|||
|
|||
// 查询参数 |
|||
const queryParams = reactive({ |
|||
jwcode: '', |
|||
markets: [], // 下拉多选 |
|||
timeRange: [], // [startTime, endTime] |
|||
payType: '', |
|||
orderCode: '', |
|||
statuses: [], |
|||
pageNum: 1, |
|||
pageSize: 50 |
|||
}) |
|||
|
|||
const total = ref(0) |
|||
const tableData = ref([]) |
|||
const loading = ref(false) |
|||
|
|||
// 转换树形结构(参考 coinConsumeDetail.vue) |
|||
const transformTree = (nodes) => { |
|||
const allChildren = nodes.flatMap(node => node.children || []); |
|||
return allChildren.map(child => { |
|||
const grandchildren = child.children && child.children.length |
|||
? transformTree([child]) |
|||
: null; |
|||
return { |
|||
value: child.name, |
|||
label: child.name, |
|||
children: grandchildren |
|||
}; |
|||
}); |
|||
}; |
|||
|
|||
// 获取地区数据 |
|||
const getMarket = async () => { |
|||
try { |
|||
const result = await request({ url: '/market/selectMarket' }); |
|||
if (result && result.data) { |
|||
marketOptions.value = transformTree(result.data) |
|||
} |
|||
} catch (error) { |
|||
console.error('获取地区失败', error) |
|||
} |
|||
} |
|||
|
|||
// 查询列表 |
|||
const fetchData = async () => { |
|||
loading.value = true |
|||
try { |
|||
// 构建请求参数 |
|||
const params = { |
|||
pageNum: queryParams.pageNum, |
|||
pageSize: queryParams.pageSize, |
|||
fundsDTO:{ |
|||
jwcode: queryParams.jwcode, |
|||
markets: queryParams.markets, |
|||
startTime: queryParams.timeRange?.[0] || '', |
|||
endTime: queryParams.timeRange?.[1] || '', |
|||
payType: queryParams.payType, |
|||
orderCode: queryParams.orderCode, |
|||
statuses: queryParams.statuses, |
|||
} |
|||
} |
|||
|
|||
console.log('查询参数:', params) |
|||
const res = await Moneyfunds(params) |
|||
if (res.code == 200) { |
|||
tableData.value = res.data.list || [] |
|||
total.value = res.data.total || 0 |
|||
loading.value = false |
|||
} else { |
|||
ElMessage.error(res.msg || '获取数据失败') |
|||
loading.value = false |
|||
} |
|||
} catch (error) { |
|||
console.error(error) |
|||
loading.value = false |
|||
ElMessage.error('获取数据失败') |
|||
} |
|||
} |
|||
|
|||
const handleSearch = () => { |
|||
queryParams.pageNum = 1 |
|||
fetchData() |
|||
} |
|||
|
|||
const handleReset = () => { |
|||
queryParams.jwcode = '' |
|||
queryParams.markets = [] |
|||
queryParams.timeRange = [] |
|||
queryParams.payType = '' |
|||
queryParams.orderCode = '' |
|||
queryParams.statuses = [] |
|||
handleSearch() |
|||
} |
|||
|
|||
const handlePageSizeChange = (val) => { |
|||
queryParams.pageSize = val |
|||
fetchData() |
|||
} |
|||
|
|||
const handleCurrentChange = (val) => { |
|||
queryParams.pageNum = val |
|||
fetchData() |
|||
} |
|||
|
|||
// 退款操作 |
|||
const handleRefund = (row) => { |
|||
ElMessageBox.confirm(`确定要对订单 ${row.systemTradeNo} 进行退款吗?`, '退款确认', { |
|||
confirmButtonText: '确定', |
|||
cancelButtonText: '取消', |
|||
type: 'warning' |
|||
}).then(() => { |
|||
|
|||
|
|||
ElMessage.success('退款申请已提交') |
|||
// 刷新列表 |
|||
fetchData() |
|||
}).catch(() => {}) |
|||
} |
|||
|
|||
// ==================== 导出相关逻辑 ==================== |
|||
|
|||
const exportListVisible = ref(false) |
|||
const exportList = ref([]) |
|||
const exportListLoading = ref(false) |
|||
|
|||
// 导出Excel |
|||
const handleExport = async () => { |
|||
try { |
|||
const params = { |
|||
pageNum: queryParams.pageNum, |
|||
pageSize: queryParams.pageSize, |
|||
fundsDTO:{ |
|||
jwcode: queryParams.jwcode, |
|||
markets: queryParams.markets, |
|||
startTime: queryParams.timeRange?.[0] || '', |
|||
endTime: queryParams.timeRange?.[1] || '', |
|||
payType: queryParams.payType, |
|||
orderCode: queryParams.orderCode, |
|||
statuses: queryParams.statuses, |
|||
} |
|||
} |
|||
|
|||
// TODO: 确认导出接口 URL |
|||
const res = await request({ url: '/export/exportCash', data: params }) |
|||
if(res.code == 200){ |
|||
|
|||
console.log('导出参数', params) |
|||
ElMessage.success(t('elmessage.exportSuccess')) |
|||
} |
|||
|
|||
} catch (error) { |
|||
console.error(error) |
|||
ElMessage.error('导出失败') |
|||
} |
|||
} |
|||
|
|||
// 打开导出列表弹窗 |
|||
const openExportList = () => { |
|||
getExportList() |
|||
exportListVisible.value = true |
|||
} |
|||
|
|||
// 获取导出列表 |
|||
const getExportList = async () => { |
|||
exportListLoading.value = true |
|||
try { |
|||
const result = await request({ url: '/export/export' }) |
|||
if (result.code === 200) { |
|||
const filteredData = result.data.filter(item => item.type == 13); |
|||
exportList.value = filteredData || [] |
|||
} else { |
|||
ElMessage.error(result.msg || t('elmessage.getExportListError')) |
|||
} |
|||
} catch (error) { |
|||
console.error('获取导出列表出错:', error) |
|||
ElMessage.error(t('elmessage.getExportListError')) |
|||
} finally { |
|||
exportListLoading.value = false |
|||
} |
|||
} |
|||
|
|||
// 下载导出文件 |
|||
const downloadExportFile = (item) => { |
|||
if (item.state === 2) { |
|||
const link = document.createElement('a') |
|||
link.href = item.url |
|||
link.download = item.fileName |
|||
link.click() |
|||
} else { |
|||
ElMessage.warning(t('elmessage.exportingInProgress')) |
|||
} |
|||
} |
|||
|
|||
// 根据状态返回对应的标签类型 |
|||
const getTagType = (state) => { |
|||
switch (state) { |
|||
case 0: return 'info'; |
|||
case 1: return 'primary'; |
|||
case 2: return 'success'; |
|||
case 3: return 'danger'; |
|||
default: return 'info'; |
|||
} |
|||
} |
|||
|
|||
// 根据状态返回对应的标签文案 |
|||
const getTagText = (state) => { |
|||
switch (state) { |
|||
case 0: return t('elmessage.pendingExecution'); |
|||
case 1: return t('elmessage.executing'); |
|||
case 2: return t('elmessage.executed'); |
|||
case 3: return t('elmessage.errorExecution'); |
|||
default: return t('elmessage.unknownStatus'); |
|||
} |
|||
} |
|||
|
|||
onMounted(() => { |
|||
getMarket() |
|||
fetchData() |
|||
}) |
|||
</script> |
|||
|
|||
<template> |
|||
<div> |
|||
<h1>资金流水</h1> |
|||
</div> |
|||
<div class="cash-flow-container"> |
|||
<!-- 搜索区域 --> |
|||
<el-card class="search-card"> |
|||
<div class="search-bar"> |
|||
<!-- 第一行 --> |
|||
<div class="search-row"> |
|||
<div class="search-item"> |
|||
<span class="label">精网号:</span> |
|||
<el-input v-model="queryParams.jwcode" placeholder="请输入精网号" clearable /> |
|||
</div> |
|||
<div class="search-item"> |
|||
<span class="label">所属地区:</span> |
|||
<!-- 下拉多选,使用 el-cascader 匹配地区树结构 --> |
|||
<el-cascader |
|||
v-model="queryParams.markets" |
|||
:options="marketOptions" |
|||
:props="{ multiple: true, emitPath: false }" |
|||
collapse-tags |
|||
collapse-tags-tooltip |
|||
placeholder="请选择地区" |
|||
clearable |
|||
style="width: 220px;" |
|||
/> |
|||
</div> |
|||
<div class="search-item"> |
|||
<span class="label">支付平台:</span> |
|||
<el-select v-model="queryParams.payType" placeholder="请选择" clearable> |
|||
<el-option v-for="item in payPlatformOptions" :key="item" :label="item" :value="item" /> |
|||
</el-select> |
|||
</div> |
|||
<div class="search-item"> |
|||
<span class="label">状态:</span> |
|||
<el-select v-model="queryParams.statuses[0]" placeholder="请选择" clearable> |
|||
<el-option v-for="item in statusOptions" :key="item.value" :label="item.label" :value="item.value" /> |
|||
</el-select> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- 第二行 --> |
|||
<div class="search-row"> |
|||
<div class="search-item"> |
|||
<span class="label">订单号:</span> |
|||
<el-input v-model="queryParams.orderCode" placeholder="请输入订单号" clearable /> |
|||
</div> |
|||
<div class="search-item" style="width: auto;"> |
|||
<span class="label">付款时间:</span> |
|||
<el-date-picker |
|||
v-model="queryParams.timeRange" |
|||
type="datetimerange" |
|||
range-separator="至" |
|||
start-placeholder="开始时间" |
|||
end-placeholder="结束时间" |
|||
:default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]" |
|||
style="width: 350px;" |
|||
/> |
|||
</div> |
|||
<div class="search-btn-group"> |
|||
<el-button type="primary" @click="handleSearch">{{ t('common.search') }}</el-button> |
|||
<el-button type="primary" @click="handleExport">{{ t('common.exportExcel') }}</el-button> |
|||
<el-button type="primary" @click="openExportList">{{ t('common.viewExportList') }}</el-button> |
|||
<el-button type="success" @click="handleReset">{{ t('common.reset') }}</el-button> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</el-card> |
|||
|
|||
<!-- 表格区域 --> |
|||
<el-card class="table-card"> |
|||
<el-table :data="tableData" v-loading="loading" style="width: 100%; flex: 1;" :header-cell-style="{ background: '#F3FAFE', color: '#333' }"> |
|||
<el-table-column type="index" label="序号" width="60" align="center" fixed="left" /> |
|||
<el-table-column prop="jwcode" label="精网号" width="120" fixed="left" /> |
|||
<el-table-column prop="name" label="姓名" width="120" show-overflow-tooltip /> |
|||
<el-table-column prop="market" label="所属地区" width="120" show-overflow-tooltip /> |
|||
<el-table-column prop="orderCode" label="系统交易号" width="180" show-overflow-tooltip /> |
|||
|
|||
<el-table-column prop="paymentAmount" label="付款金额" width="150" align="right"> |
|||
<!-- <template #default="{ row }"> |
|||
{{ row.paymentAmount }} {{ row.paymentCurrency }} |
|||
</template> --> |
|||
</el-table-column> |
|||
<el-table-column prop="paymentCurrency" label="付款币种" width="180" show-overflow-tooltip /> |
|||
|
|||
<el-table-column prop="receivedAmount" label="到账金额" width="150" align="right"> |
|||
<!-- <template #default="{ row }"> |
|||
{{ row.receivedAmount }} {{ row.receivedCurrency }} |
|||
</template> --> |
|||
</el-table-column> |
|||
<el-table-column prop="receivedCurrency" label="到账币种" width="180" show-overflow-tooltip /> |
|||
|
|||
<el-table-column prop="handlingCharge" label="手续费" width="100" align="right" /> |
|||
<el-table-column prop="payType" label="支付方式" width="120" align="center" /> |
|||
<el-table-column prop="payTime" label="付款时间" width="180" align="center" /> |
|||
|
|||
<el-table-column prop="status" label="状态" width="100" align="center" fixed="right"> |
|||
<template #default="{ row }"> |
|||
<el-tag :type="row.status === 4 ? 'success' : 'warning'" effect="plain"> |
|||
{{ row.status === 4 ? '已到账' : '已退款' }} |
|||
</el-tag> |
|||
</template> |
|||
</el-table-column> |
|||
|
|||
<el-table-column label="操作" width="100" fixed="right" align="center"> |
|||
<template #default="{ row }"> |
|||
<el-button |
|||
v-if="row.orderCode.slice(0,4) == 'GOLD'" |
|||
type="danger" |
|||
link |
|||
size="small" |
|||
@click="handleRefund(row)" |
|||
> |
|||
退款 |
|||
</el-button> |
|||
</template> |
|||
</el-table-column> |
|||
</el-table> |
|||
|
|||
<!-- 分页 --> |
|||
<div class="pagination-container"> |
|||
<el-pagination |
|||
background |
|||
layout="total, sizes, prev, pager, next, jumper" |
|||
:total="total" |
|||
:current-page="queryParams.pageNum" |
|||
:page-size="queryParams.pageSize" |
|||
:page-sizes="[10, 20, 50, 100]" |
|||
@size-change="handlePageSizeChange" |
|||
@current-change="handleCurrentChange" |
|||
/> |
|||
</div> |
|||
</el-card> |
|||
|
|||
<!-- 导出列表弹窗 --> |
|||
<el-dialog v-model="exportListVisible" :title="t('common_export.exportList')" width="80%"> |
|||
<el-table :data="exportList" style="width: 100% ;height: 60vh;" :loading="exportListLoading"> |
|||
<el-table-column prop="fileName" :label="t('common_export.fileName')" /> |
|||
<el-table-column prop="state" :label="t('common_export.status')"> |
|||
<template #default="scope"> |
|||
<el-tag :type="getTagType(scope.row.state)" :effect="scope.row.state === 3 ? 'light' : 'plain'"> |
|||
{{ getTagText(scope.row.state) }} |
|||
</el-tag> |
|||
</template> |
|||
</el-table-column> |
|||
<el-table-column prop="createTime" :label="t('common_export.createTime')"> |
|||
<template #default="scope"> |
|||
{{ dayjs(scope.row.createTime).format('YYYY-MM-DD HH:mm:ss') }} |
|||
</template> |
|||
</el-table-column> |
|||
<el-table-column :label="t('common_export.operation')"> |
|||
<template #default="scope"> |
|||
<el-button type="primary" size="small" @click="downloadExportFile(scope.row)" |
|||
:disabled="scope.row.state !== 2"> |
|||
{{ t('common_export.download') }} |
|||
</el-button> |
|||
</template> |
|||
</el-table-column> |
|||
</el-table> |
|||
<template #footer> |
|||
<div class="dialog-footer"> |
|||
<el-button text @click="exportListVisible = false">{{ t('common_export.close') }}</el-button> |
|||
</div> |
|||
</template> |
|||
</el-dialog> |
|||
</div> |
|||
</template> |
|||
|
|||
<style scoped lang="scss"> |
|||
.cash-flow-container { |
|||
display: flex; |
|||
flex-direction: column; |
|||
height: 100%; |
|||
} |
|||
|
|||
.search-card { |
|||
margin-bottom: 10px; |
|||
background: #F3FAFE; // 浅蓝背景 |
|||
border: none; |
|||
|
|||
:deep(.el-card__body) { |
|||
padding: 15px; |
|||
} |
|||
} |
|||
|
|||
.search-bar { |
|||
display: flex; |
|||
flex-direction: column; |
|||
gap: 15px; |
|||
} |
|||
|
|||
.search-row { |
|||
display: flex; |
|||
flex-wrap: wrap; |
|||
gap: 20px; |
|||
align-items: center; |
|||
} |
|||
|
|||
.search-item { |
|||
display: flex; |
|||
align-items: center; |
|||
|
|||
.label { |
|||
font-size: 15px; // 参考 coinConsumeDetail 的 .text size="large" |
|||
color: #000; // 或 #606266 |
|||
white-space: nowrap; |
|||
margin-right: 8px; |
|||
min-width: 60px; |
|||
text-align: right; |
|||
} |
|||
|
|||
.el-input, .el-select { |
|||
width: 200px; |
|||
} |
|||
} |
|||
|
|||
.search-btn-group { |
|||
margin-left: auto; // 靠右对齐 |
|||
display: flex; |
|||
gap: 10px; |
|||
} |
|||
|
|||
.table-card { |
|||
background: #E7F4FD; |
|||
flex: 1; |
|||
border: none; |
|||
display: flex; |
|||
flex-direction: column; |
|||
|
|||
:deep(.el-card__body) { |
|||
padding: 20px; |
|||
flex: 1; |
|||
display: flex; |
|||
flex-direction: column; |
|||
overflow: hidden; |
|||
} |
|||
} |
|||
|
|||
.pagination-container { |
|||
margin-top: 15px; |
|||
display: flex; |
|||
justify-content: flex-start; |
|||
} |
|||
|
|||
// 表格样式覆盖 (参考 coinConsumeDetail) |
|||
:deep(.el-table__header-wrapper), |
|||
:deep(.el-table__body-wrapper), |
|||
:deep(.el-table__cell), |
|||
:deep(.el-table__body td) { |
|||
background-color: #F3FAFE !important; // 如果想完全一致可以加这个,但有时候会影响阅读,暂保留头部颜色 |
|||
} |
|||
|
|||
:deep(.el-table__row:hover > .el-table__cell) { |
|||
background-color: #E5EBFE !important; |
|||
} |
|||
</style> |
|||
@ -1,5 +1,509 @@ |
|||
<script setup> |
|||
import { ref, reactive, onMounted } from 'vue' |
|||
import { ElMessage, ElMessageBox } from 'element-plus' |
|||
import request from '@/util/http.js' |
|||
import dayjs from 'dayjs' |
|||
import { useI18n } from 'vue-i18n' |
|||
import { Moneyfunds,refundOnline } from '@/api/cash/financialAccount.js' |
|||
|
|||
const { t } = useI18n() |
|||
|
|||
const paytypeList = [ |
|||
t('cash.payMethods.stripe'), |
|||
t('cash.payMethods.paymentAsia'), |
|||
t('cash.payMethods.ipay88'), |
|||
t('cash.payMethods.bankTransfer'), |
|||
t('cash.payMethods.card'), |
|||
t('cash.payMethods.cash'), |
|||
t('cash.payMethods.check'), |
|||
t('cash.payMethods.grabpay'), |
|||
t('cash.payMethods.nets'), |
|||
t('cash.payMethods.transfer'), |
|||
t('cash.payMethods.paypal'), |
|||
] |
|||
|
|||
const payPlatformOptions = ref([...paytypeList]) |
|||
|
|||
const statusOptions = [ |
|||
{ label: '已到账', value: 4 }, |
|||
{ label: '已退款', value: 6 } |
|||
] |
|||
|
|||
// 地区树 |
|||
const marketOptions = ref([]) |
|||
|
|||
// 查询参数 |
|||
const queryParams = reactive({ |
|||
jwcode: '', |
|||
markets: [], // 下拉多选 |
|||
timeRange: [], // [startTime, endTime] |
|||
payType: '', |
|||
orderCode: '', |
|||
statuses: [], |
|||
pageNum: 1, |
|||
pageSize: 50 |
|||
}) |
|||
|
|||
const total = ref(0) |
|||
const tableData = ref([]) |
|||
const loading = ref(false) |
|||
|
|||
// 转换树形结构(参考 coinConsumeDetail.vue) |
|||
const transformTree = (nodes) => { |
|||
const allChildren = nodes.flatMap(node => node.children || []); |
|||
return allChildren.map(child => { |
|||
const grandchildren = child.children && child.children.length |
|||
? transformTree([child]) |
|||
: null; |
|||
return { |
|||
value: child.name, |
|||
label: child.name, |
|||
children: grandchildren |
|||
}; |
|||
}); |
|||
}; |
|||
|
|||
// 获取地区数据 |
|||
const getMarket = async () => { |
|||
try { |
|||
const result = await request({ url: '/market/selectMarket' }); |
|||
if (result && result.data) { |
|||
marketOptions.value = transformTree(result.data) |
|||
} |
|||
} catch (error) { |
|||
console.error('获取地区失败', error) |
|||
} |
|||
} |
|||
|
|||
// 查询列表 |
|||
const fetchData = async () => { |
|||
loading.value = true |
|||
try { |
|||
// 构建请求参数 |
|||
const params = { |
|||
pageNum: queryParams.pageNum, |
|||
pageSize: queryParams.pageSize, |
|||
fundsDTO:{ |
|||
jwcode: queryParams.jwcode, |
|||
markets: queryParams.markets, |
|||
startTime: queryParams.timeRange?.[0] || '', |
|||
endTime: queryParams.timeRange?.[1] || '', |
|||
payType: queryParams.payType, |
|||
orderCode: queryParams.orderCode, |
|||
statuses: queryParams.statuses, |
|||
} |
|||
} |
|||
|
|||
console.log('查询参数:', params) |
|||
const res = await Moneyfunds(params) |
|||
if (res.code == 200) { |
|||
tableData.value = res.data.list || [] |
|||
total.value = res.data.total || 0 |
|||
loading.value = false |
|||
} else { |
|||
ElMessage.error(res.msg || '获取数据失败') |
|||
loading.value = false |
|||
} |
|||
} catch (error) { |
|||
console.error(error) |
|||
loading.value = false |
|||
ElMessage.error('获取数据失败') |
|||
} |
|||
} |
|||
|
|||
const handleSearch = () => { |
|||
queryParams.pageNum = 1 |
|||
fetchData() |
|||
} |
|||
|
|||
const handleReset = () => { |
|||
queryParams.jwcode = '' |
|||
queryParams.markets = [] |
|||
queryParams.timeRange = [] |
|||
queryParams.payType = '' |
|||
queryParams.orderCode = '' |
|||
queryParams.statuses = [] |
|||
handleSearch() |
|||
} |
|||
|
|||
const handlePageSizeChange = (val) => { |
|||
queryParams.pageSize = val |
|||
fetchData() |
|||
} |
|||
|
|||
const handleCurrentChange = (val) => { |
|||
queryParams.pageNum = val |
|||
fetchData() |
|||
} |
|||
|
|||
// 退款操作 |
|||
const handleRefund = (row) => { |
|||
ElMessageBox.confirm(`确定要对订单 ${row.systemTradeNo} 进行退款吗?`, '退款确认', { |
|||
confirmButtonText: '确定', |
|||
cancelButtonText: '取消', |
|||
type: 'warning' |
|||
}).then(() => { |
|||
|
|||
|
|||
ElMessage.success('退款申请已提交') |
|||
// 刷新列表 |
|||
fetchData() |
|||
}).catch(() => {}) |
|||
} |
|||
|
|||
// ==================== 导出相关逻辑 ==================== |
|||
|
|||
const exportListVisible = ref(false) |
|||
const exportList = ref([]) |
|||
const exportListLoading = ref(false) |
|||
|
|||
// 导出Excel |
|||
const handleExport = async () => { |
|||
try { |
|||
const params = { |
|||
pageNum: queryParams.pageNum, |
|||
pageSize: queryParams.pageSize, |
|||
fundsDTO:{ |
|||
jwcode: queryParams.jwcode, |
|||
markets: queryParams.markets, |
|||
startTime: queryParams.timeRange?.[0] || '', |
|||
endTime: queryParams.timeRange?.[1] || '', |
|||
payType: queryParams.payType, |
|||
orderCode: queryParams.orderCode, |
|||
statuses: queryParams.statuses, |
|||
} |
|||
} |
|||
|
|||
// TODO: 确认导出接口 URL |
|||
const res = await request({ url: '/export/exportCash', data: params }) |
|||
if(res.code == 200){ |
|||
|
|||
console.log('导出参数', params) |
|||
ElMessage.success(t('elmessage.exportSuccess')) |
|||
} |
|||
|
|||
} catch (error) { |
|||
console.error(error) |
|||
ElMessage.error('导出失败') |
|||
} |
|||
} |
|||
|
|||
// 打开导出列表弹窗 |
|||
const openExportList = () => { |
|||
getExportList() |
|||
exportListVisible.value = true |
|||
} |
|||
|
|||
// 获取导出列表 |
|||
const getExportList = async () => { |
|||
exportListLoading.value = true |
|||
try { |
|||
const result = await request({ url: '/export/export' }) |
|||
if (result.code === 200) { |
|||
const filteredData = result.data.filter(item => item.type == 13); |
|||
exportList.value = filteredData || [] |
|||
} else { |
|||
ElMessage.error(result.msg || t('elmessage.getExportListError')) |
|||
} |
|||
} catch (error) { |
|||
console.error('获取导出列表出错:', error) |
|||
ElMessage.error(t('elmessage.getExportListError')) |
|||
} finally { |
|||
exportListLoading.value = false |
|||
} |
|||
} |
|||
|
|||
// 下载导出文件 |
|||
const downloadExportFile = (item) => { |
|||
if (item.state === 2) { |
|||
const link = document.createElement('a') |
|||
link.href = item.url |
|||
link.download = item.fileName |
|||
link.click() |
|||
} else { |
|||
ElMessage.warning(t('elmessage.exportingInProgress')) |
|||
} |
|||
} |
|||
|
|||
// 根据状态返回对应的标签类型 |
|||
const getTagType = (state) => { |
|||
switch (state) { |
|||
case 0: return 'info'; |
|||
case 1: return 'primary'; |
|||
case 2: return 'success'; |
|||
case 3: return 'danger'; |
|||
default: return 'info'; |
|||
} |
|||
} |
|||
|
|||
// 根据状态返回对应的标签文案 |
|||
const getTagText = (state) => { |
|||
switch (state) { |
|||
case 0: return t('elmessage.pendingExecution'); |
|||
case 1: return t('elmessage.executing'); |
|||
case 2: return t('elmessage.executed'); |
|||
case 3: return t('elmessage.errorExecution'); |
|||
default: return t('elmessage.unknownStatus'); |
|||
} |
|||
} |
|||
|
|||
onMounted(() => { |
|||
getMarket() |
|||
fetchData() |
|||
}) |
|||
</script> |
|||
|
|||
<template> |
|||
<div> |
|||
<h1>业绩归属</h1> |
|||
</div> |
|||
<div class="cash-flow-container"> |
|||
<!-- 搜索区域 --> |
|||
<el-card class="search-card"> |
|||
<div class="search-bar"> |
|||
<!-- 第一行 --> |
|||
<div class="search-row"> |
|||
<div class="search-item"> |
|||
<span class="label">精网号:</span> |
|||
<el-input v-model="queryParams.jwcode" placeholder="请输入精网号" clearable /> |
|||
</div> |
|||
<div class="search-item"> |
|||
<span class="label">所属地区:</span> |
|||
<!-- 下拉多选,使用 el-cascader 匹配地区树结构 --> |
|||
<el-cascader |
|||
v-model="queryParams.markets" |
|||
:options="marketOptions" |
|||
:props="{ multiple: true, emitPath: false }" |
|||
collapse-tags |
|||
collapse-tags-tooltip |
|||
placeholder="请选择地区" |
|||
clearable |
|||
style="width: 220px;" |
|||
/> |
|||
</div> |
|||
<div class="search-item"> |
|||
<span class="label">支付平台:</span> |
|||
<el-select v-model="queryParams.payType" placeholder="请选择" clearable> |
|||
<el-option v-for="item in payPlatformOptions" :key="item" :label="item" :value="item" /> |
|||
</el-select> |
|||
</div> |
|||
<div class="search-item"> |
|||
<span class="label">状态:</span> |
|||
<el-select v-model="queryParams.statuses[0]" placeholder="请选择" clearable> |
|||
<el-option v-for="item in statusOptions" :key="item.value" :label="item.label" :value="item.value" /> |
|||
</el-select> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- 第二行 --> |
|||
<div class="search-row"> |
|||
<div class="search-item"> |
|||
<span class="label">订单号:</span> |
|||
<el-input v-model="queryParams.orderCode" placeholder="请输入订单号" clearable /> |
|||
</div> |
|||
<div class="search-item" style="width: auto;"> |
|||
<span class="label">付款时间:</span> |
|||
<el-date-picker |
|||
v-model="queryParams.timeRange" |
|||
type="datetimerange" |
|||
range-separator="至" |
|||
start-placeholder="开始时间" |
|||
end-placeholder="结束时间" |
|||
:default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]" |
|||
style="width: 350px;" |
|||
/> |
|||
</div> |
|||
<div class="search-btn-group"> |
|||
<el-button type="primary" @click="handleSearch">{{ t('common.search') }}</el-button> |
|||
<el-button type="primary" @click="handleExport">{{ t('common.exportExcel') }}</el-button> |
|||
<el-button type="primary" @click="openExportList">{{ t('common.viewExportList') }}</el-button> |
|||
<el-button type="success" @click="handleReset">{{ t('common.reset') }}</el-button> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</el-card> |
|||
|
|||
<!-- 表格区域 --> |
|||
<el-card class="table-card"> |
|||
<el-table :data="tableData" v-loading="loading" style="width: 100%; flex: 1;" :header-cell-style="{ background: '#F3FAFE', color: '#333' }"> |
|||
<el-table-column type="index" label="序号" width="60" align="center" fixed="left" /> |
|||
<el-table-column prop="jwcode" label="精网号" width="120" fixed="left" /> |
|||
<el-table-column prop="name" label="姓名" width="120" show-overflow-tooltip /> |
|||
<el-table-column prop="market" label="所属地区" width="120" show-overflow-tooltip /> |
|||
<el-table-column prop="orderCode" label="系统交易号" width="180" show-overflow-tooltip /> |
|||
|
|||
<el-table-column prop="paymentAmount" label="付款金额" width="150" align="right"> |
|||
<!-- <template #default="{ row }"> |
|||
{{ row.paymentAmount }} {{ row.paymentCurrency }} |
|||
</template> --> |
|||
</el-table-column> |
|||
<el-table-column prop="paymentCurrency" label="付款币种" width="180" show-overflow-tooltip /> |
|||
|
|||
<el-table-column prop="receivedAmount" label="到账金额" width="150" align="right"> |
|||
<!-- <template #default="{ row }"> |
|||
{{ row.receivedAmount }} {{ row.receivedCurrency }} |
|||
</template> --> |
|||
</el-table-column> |
|||
<el-table-column prop="receivedCurrency" label="到账币种" width="180" show-overflow-tooltip /> |
|||
|
|||
<el-table-column prop="handlingCharge" label="手续费" width="100" align="right" /> |
|||
<el-table-column prop="payType" label="支付方式" width="120" align="center" /> |
|||
<el-table-column prop="payTime" label="付款时间" width="180" align="center" /> |
|||
|
|||
<el-table-column prop="status" label="状态" width="100" align="center" fixed="right"> |
|||
<template #default="{ row }"> |
|||
<el-tag :type="row.status === 4 ? 'success' : 'warning'" effect="plain"> |
|||
{{ row.status === 4 ? '已到账' : '已退款' }} |
|||
</el-tag> |
|||
</template> |
|||
</el-table-column> |
|||
|
|||
<el-table-column label="操作" width="100" fixed="right" align="center"> |
|||
<template #default="{ row }"> |
|||
<el-button |
|||
v-if="row.orderCode.slice(0,4) == 'GOLD'" |
|||
type="danger" |
|||
link |
|||
size="small" |
|||
@click="handleRefund(row)" |
|||
> |
|||
退款 |
|||
</el-button> |
|||
</template> |
|||
</el-table-column> |
|||
</el-table> |
|||
|
|||
<!-- 分页 --> |
|||
<div class="pagination-container"> |
|||
<el-pagination |
|||
background |
|||
layout="total, sizes, prev, pager, next, jumper" |
|||
:total="total" |
|||
:current-page="queryParams.pageNum" |
|||
:page-size="queryParams.pageSize" |
|||
:page-sizes="[10, 20, 50, 100]" |
|||
@size-change="handlePageSizeChange" |
|||
@current-change="handleCurrentChange" |
|||
/> |
|||
</div> |
|||
</el-card> |
|||
|
|||
<!-- 导出列表弹窗 --> |
|||
<el-dialog v-model="exportListVisible" :title="t('common_export.exportList')" width="80%"> |
|||
<el-table :data="exportList" style="width: 100% ;height: 60vh;" :loading="exportListLoading"> |
|||
<el-table-column prop="fileName" :label="t('common_export.fileName')" /> |
|||
<el-table-column prop="state" :label="t('common_export.status')"> |
|||
<template #default="scope"> |
|||
<el-tag :type="getTagType(scope.row.state)" :effect="scope.row.state === 3 ? 'light' : 'plain'"> |
|||
{{ getTagText(scope.row.state) }} |
|||
</el-tag> |
|||
</template> |
|||
</el-table-column> |
|||
<el-table-column prop="createTime" :label="t('common_export.createTime')"> |
|||
<template #default="scope"> |
|||
{{ dayjs(scope.row.createTime).format('YYYY-MM-DD HH:mm:ss') }} |
|||
</template> |
|||
</el-table-column> |
|||
<el-table-column :label="t('common_export.operation')"> |
|||
<template #default="scope"> |
|||
<el-button type="primary" size="small" @click="downloadExportFile(scope.row)" |
|||
:disabled="scope.row.state !== 2"> |
|||
{{ t('common_export.download') }} |
|||
</el-button> |
|||
</template> |
|||
</el-table-column> |
|||
</el-table> |
|||
<template #footer> |
|||
<div class="dialog-footer"> |
|||
<el-button text @click="exportListVisible = false">{{ t('common_export.close') }}</el-button> |
|||
</div> |
|||
</template> |
|||
</el-dialog> |
|||
</div> |
|||
</template> |
|||
|
|||
<style scoped lang="scss"> |
|||
.cash-flow-container { |
|||
display: flex; |
|||
flex-direction: column; |
|||
height: 100%; |
|||
} |
|||
|
|||
.search-card { |
|||
margin-bottom: 10px; |
|||
background: #F3FAFE; // 浅蓝背景 |
|||
border: none; |
|||
|
|||
:deep(.el-card__body) { |
|||
padding: 15px; |
|||
} |
|||
} |
|||
|
|||
.search-bar { |
|||
display: flex; |
|||
flex-direction: column; |
|||
gap: 15px; |
|||
} |
|||
|
|||
.search-row { |
|||
display: flex; |
|||
flex-wrap: wrap; |
|||
gap: 20px; |
|||
align-items: center; |
|||
} |
|||
|
|||
.search-item { |
|||
display: flex; |
|||
align-items: center; |
|||
|
|||
.label { |
|||
font-size: 15px; // 参考 coinConsumeDetail 的 .text size="large" |
|||
color: #000; // 或 #606266 |
|||
white-space: nowrap; |
|||
margin-right: 8px; |
|||
min-width: 60px; |
|||
text-align: right; |
|||
} |
|||
|
|||
.el-input, .el-select { |
|||
width: 200px; |
|||
} |
|||
} |
|||
|
|||
.search-btn-group { |
|||
margin-left: auto; // 靠右对齐 |
|||
display: flex; |
|||
gap: 10px; |
|||
} |
|||
|
|||
.table-card { |
|||
background: #E7F4FD; |
|||
flex: 1; |
|||
border: none; |
|||
display: flex; |
|||
flex-direction: column; |
|||
|
|||
:deep(.el-card__body) { |
|||
padding: 20px; |
|||
flex: 1; |
|||
display: flex; |
|||
flex-direction: column; |
|||
overflow: hidden; |
|||
} |
|||
} |
|||
|
|||
.pagination-container { |
|||
margin-top: 15px; |
|||
display: flex; |
|||
justify-content: flex-start; |
|||
} |
|||
|
|||
// 表格样式覆盖 (参考 coinConsumeDetail) |
|||
:deep(.el-table__header-wrapper), |
|||
:deep(.el-table__body-wrapper), |
|||
:deep(.el-table__cell), |
|||
:deep(.el-table__body td) { |
|||
background-color: #F3FAFE !important; // 如果想完全一致可以加这个,但有时候会影响阅读,暂保留头部颜色 |
|||
} |
|||
|
|||
:deep(.el-table__row:hover > .el-table__cell) { |
|||
background-color: #E5EBFE !important; |
|||
} |
|||
</style> |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue