金币系统前端
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

794 lines
22 KiB

<template>
<!-- 这是金豆充值明细页面 -->
<div class="filter-box">
<el-form :model="detailY" ref="ruleFormRef">
<el-form-item prop="jwcode">
<el-text class="mx-1" size="large">精网号</el-text>
<el-input
v-model="detailY.jwcode"
placeholder="请输入精网号"
style="width: 220px"
/>
</el-form-item>
<el-form-item prop="deptName" >
<el-text class="mx-1" size="large">地区:</el-text>
<el-select
v-model="detailY.deptName"
placeholder="请选择所属地区"
style="width: 240px"
clearable
>
<el-option
v-for="item in areaList"
:key="item"
:label="item"
:value="item"
/>
</el-select>
</el-form-item>
<el-form-item prop="orderNo" >
<el-text class="mx-1" size="large">订单号:</el-text>
<el-input
v-model="detailY.orderNo"
placeholder="请输入订单号"
style="width: 220px"
/>
</el-form-item>
<el-form-item prop="type">
<el-text class="mx-1" size="large">充值类型:</el-text>
<el-select
v-model="detailY.type"
placeholder="请选择充值类型"
style="width: 240px"
clearable
>
<el-option
v-for="item in typeList"
:key="item"
:label="item"
:value="item"
/>
</el-select>
</el-form-item>
<!-- <el-form-item prop="payStyle" label="充值平台">
<el-select
v-model="detailY.payStyle"
placeholder="请选择充值平台"
style="width: 240px"
clearable
>
<el-option
v-for="item in platformList"
:key="item"
:label="item"
:value="item"
/>
</el-select>
</el-form-item> -->
<el-row :span="24">
<el-form-item prop="startTime">
<el-text class="mx-1" size="large">开始时间</el-text>
<el-date-picker
v-model="detailY.startTime"
type="date"
placeholder="开始日期"
style="width: 240px"
format="YYYY-MM-DD HH:mm:ss"
value-format="YYYY-MM-DD HH:mm:ss"
/>
</el-form-item>
<el-form-item prop="endTime">
<el-text class="mx-1" size="large">结束时间:</el-text>
<el-date-picker
v-model="detailY.endTime"
type="date"
placeholder="结束日期"
style="width: 240px"
format="YYYY-MM-DD HH:mm:ss"
value-format="YYYY-MM-DD HH:mm:ss"
/>
</el-form-item>
<el-button style="margin-left: 10px" @click="getToday()">今</el-button>
<el-button @click="getYesterday()">昨</el-button>
<el-button @click="get7Days()">近7天</el-button>
</el-row>
<el-form-item>
<el-button type="primary" @click="search">查询</el-button>
<el-button type="success" @click="reset(ruleFormRef)">重置</el-button>
<el-button type="primary" @click="showExportInfoPanel = true">导出excel</el-button>
</el-form-item>
</el-form>
</div>
<!-- 导出excel提前展示的信息面板 -->
<el-dialog
v-model="showExportInfoPanel"
title="导出信息确认"
width="400px"
:close-on-click-modal="false"
>
<div class="info-panel-header">导出信息</div>
<div v-if="!detailY.jwcode && !detailY.deptName && !detailY.orderNo && !detailY.type && !detailY.startTime && !detailY.endTime">
你正在导出所有数据
</div>
<div v-else>
你正在导出以下数据
</div>
<div v-if="detailY.jwcode">精网号:{{ detailY.jwcode || '' }}</div>
<div v-if="detailY.deptName">所属地区:{{ detailY.deptName || '' }}</div>
<div v-if="detailY.orderNo">订单号:{{ detailY.orderNo || '' }}</div>
<div v-if="detailY.type">充值类型:{{ detailY.type || '' }}</div>
<div v-if="detailY.startTime || detailY.endTime">
<span>更新时间:</span>
<span>{{ detailY.startTime || '无起始时间' }} 至 {{ detailY.endTime || '无结束时间' }}</span>
</div>
<template #footer>
<span class="dialog-footer">
<el-button @click="showExportInfoPanel = false">取消</el-button>
<el-button type="primary" @click="doExportExcel">导出</el-button>
</span>
</template>
</el-dialog>
<!-- 导出进度弹窗 -->
<el-dialog
v-model="isExporting"
title="正在导出"
width="400px"
:close-on-click-modal="false"
:show-close="false"
>
<el-progress
:percentage="exportProgress"
:stroke-width="15"
striped
animated
/>
<div class="export-status">
已导出 {{ exportedCount }} 条 / 共 {{ totalExport }} 条
</div>
<template #footer>
<el-button type="danger" @click="cancelExport">取消导出</el-button>
</template>
</el-dialog>
<div class="table-box">
<div
>金豆总数:充值金豆总数:{{ countValue }},合计金额数:{{
priceValue
}}</div
>
<el-table :data="tableData" style="width: 100%" height="584px">
<el-table-column type="index" label="序号" width="100px" fixed="left">
<template #default="scope">
<span>{{
scope.$index + 1 + (getObj.pageNum - 1) * getObj.pageSize
}}</span>
</template>
</el-table-column>
<el-table-column fixed="left" prop="nickname" label="姓名" width="150" />
<el-table-column fixed="left" prop="jwcode" label="精网号" width="120" />
<el-table-column prop="ipAddress" label="地区" width="120" />
<el-table-column prop="orderNo" label="订单号" width="120" />
<el-table-column prop="money" label="金豆数量" width="120">
</el-table-column>
<el-table-column prop="moneyBuy" label="付费金豆" width="120">
</el-table-column>
<el-table-column prop="moneyFree" label="免费金豆" width="120">
</el-table-column>
<el-table-column prop="price" label="金额"></el-table-column>
<el-table-column prop="type" label="类型"></el-table-column>
<!-- <el-table-column prop="payStyle" label="充值平台" width="140">
</el-table-column>
<el-table-column prop="notes" label="备注" width="210"></el-table-column> -->
<el-table-column
prop="time"
label="充值时间"
width="210"
show-overflow-tooltip
>
<template #default="scope">
<span>{{
!!scope.row.time
? moment.unix(scope.row.time).format('YYYY-MM-DD HH:mm:ss')
: '-'
}}</span>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<div class="pagination">
<el-pagination
background
:page-size="getObj.pageSize"
:page-sizes="[5, 10, 20, 50, 100]"
layout="total, sizes, prev, pager, next, jumper"
:total="total"
@size-change="handlePageSizeChange"
@current-change="handleCurrentChange"
>
</el-pagination>
</div>
</div>
<!-- 这是导出excel的弹窗 -->
<!-- <el-dialog
v-model="dialogVisible"
title="请选择导出条件"
width="500"
:close-on-click-modal="false"
@close="
() => {
dialogVisible = false
isExport = false
}
"
>
<template #footer>
<el-form
ref="ruleFormRef"
style="max-width: 600px"
:model="excelData"
:rules="rules"
label-width="auto"
class="demo-ruleForm"
status-icon
>
<el-form-item prop="activityName" label="精网号:">
<el-input
v-model="excelData.jwcode"
placeholder="请输入精网号"
style="width: 220px"
/>
</el-form-item>
<el-form-item label="所属地区:"
><el-select
v-model="excelData.area"
placeholder="请选择所属地区"
style="width: 240px"
clearable
>
<el-option
v-for="item in areaList"
:key="item"
:label="item"
:value="item"
/>
</el-select>
</el-form-item>
<el-form-item label="更新时间:">
<el-radio-group v-model="excelData.timegap">
<el-radio value="1">今天</el-radio>
<el-radio value="3">近三天</el-radio>
<el-radio value="7">近一周</el-radio>
<el-radio value="30">近一个月</el-radio>
</el-radio-group>
</el-form-item>
<el-button
type="primary"
size="small"
style="margin-left: 10px"
@click="exportConfirm()"
>确定</el-button
>
</el-form>
</template>
</el-dialog> -->
</template>
<script setup lang="ts">
import { reactive, ref, onMounted, onUnmounted } from 'vue'
import { FormInstance } from 'element-plus'
import { ElMessage } from 'element-plus'
import moment from 'moment'
import API from '@/util/http'
import { utils, write } from 'xlsx'
import { saveAs } from 'file-saver'
const showExportInfoPanel = ref(false)
const isExporting = ref(false)
const exportProgress = ref(0)
const totalExport = ref(0)
const exportedCount = ref(0)
let cancelToken: any = null
let allExportData: any[] = []
// 取消导出
const cancelExport = () => {
if (cancelToken) {
cancelToken.cancel('导出已取消')
}
isExporting.value = false
exportProgress.value = 0
exportedCount.value = 0
allExportData = []
ElMessage.info('导出已取消')
}
// 导出 Excel
const doExportExcel = async () => {
try {
isExporting.value = true
exportProgress.value = 0
exportedCount.value = 0
allExportData = []
// 获取总数据量
const totalResult = await API({
url: '/dou/getPay',
data: {
pay: {
jwcode: detailY.value.jwcode,
deptName: detailY.value.deptName,
startTime: detailY.value.startTime || '',
endTime: detailY.value.endTime || '',
payStyle: detailY.value.payStyle,
type: detailY.value.type,
orderNo: detailY.value.orderNo,
sortField: '',
sortOrder: ''
},
pageNum: 1,
pageSize: 1
}
})
totalExport.value = totalResult.data.total
if (totalExport.value === 0) {
ElMessage.error('没有数据可导出')
isExporting.value = false
return
}
const pageSize = 5000 // 每批次获取 100 条数据
const totalPages = Math.ceil(totalExport.value / pageSize)
for (let page = 1; page <= totalPages; page++) {
if (!isExporting.value) break // 如果取消导出,停止循环
const result = await API({
url: '/dou/getPay',
data: {
pay: {
jwcode: detailY.value.jwcode,
deptName: detailY.value.deptName,
startTime: detailY.value.startTime || '',
endTime: detailY.value.endTime || '',
payStyle: detailY.value.payStyle,
type: detailY.value.type,
orderNo: detailY.value.orderNo,
sortField: '',
sortOrder: ''
},
pageNum: page,
pageSize: pageSize
}
})
const data = result.data.list
allExportData = allExportData.concat(data)
exportedCount.value = allExportData.length
exportProgress.value = Math.round((exportedCount.value / totalExport.value) * 100)
}
if (isExporting.value) {
// 导出的数据将字段映射,添加序号列
const exportData = allExportData.map((item, index) => {
return {
序号: index + 1, // 添加序号列
姓名: item.nickname,
精网号: item.jwcode,
地区: item.ipAddress,
订单号: item.orderNo,
金豆数量: item.money,
付费金豆: item.moneyBuy,
免费金豆: item.moneyFree,
金额: item.price,
类型: item.type,
充值时间: !!item.time ? moment.unix(item.time).format('YYYY-MM-DD HH:mm:ss') : '-'
}
})
const worksheet = utils.json_to_sheet(exportData)
const workbook = utils.book_new()
utils.book_append_sheet(workbook, worksheet, 'Sheet1')
const wbout = write(workbook, { bookType: 'xlsx', type: 'array' })
saveAs(
new Blob([wbout], { type: 'application/octet-stream' }),
'金豆充值明细导出.xlsx'
)
showExportInfoPanel.value = false
isExporting.value = false
ElMessage.success('导出成功')
}
} catch (error) {
if (error.message === '导出已取消') {
return
}
console.log('导出失败', error)
isExporting.value = false
ElMessage.error('导出失败,请稍后重试')
}
}
// 充值明细表格
const tableData = ref([])
//分页总条目
const total = ref(100)
const dialogVisible = ref(false)
const excelData = reactive({
jwcode: '',
area: '',
timegap: '',
startTime: '',
endTime: ''
})
const priceValue = ref(0)
const countValue = ref(0)
// areaList 地区列表
const areaList = ref<string[]>([])
const isExport = ref<boolean>(false)
const rules = ref({
jwcode: [{ required: true, message: '请输入精网号', trigger: 'blur' }],
area: [{ required: true, message: '请选择所属地区', trigger: 'change' }]
})
// 今天
const getToday = function () {
const today = new Date()
// 格式化开始时间
const startDate = moment(today).startOf('day').format('YYYY-MM-DD HH:mm:ss')
// 格式化结束时间
const endDate = moment(today).endOf('day').format('YYYY-MM-DD HH:mm:ss')
detailY.value.startTime = startDate
detailY.value.endTime = endDate
search()
}
// 昨天
const getYesterday = function () {
const yesterday = moment().subtract(1, 'days')
// 格式化开始时间
const startDate = yesterday.startOf('day').format('YYYY-MM-DD HH:mm:ss')
// 格式化结束时间
const endDate = yesterday.endOf('day').format('YYYY-MM-DD HH:mm:ss')
detailY.value.startTime = startDate
detailY.value.endTime = endDate
search()
}
// 近7天
const get7Days = function () {
// 格式化开始时间
const startDate = moment().subtract(6, 'days').startOf('day').format('YYYY-MM-DD HH:mm:ss')
// 格式化结束时间
const endDate = moment().endOf('day').format('YYYY-MM-DD HH:mm:ss')
detailY.value.startTime = startDate
detailY.value.endTime = endDate
search()
}
//获取地区接口
const getArea = async () => {
try {
const result = await API({
url: '/dou/getPayIp'
})
areaList.value = result.data
} catch (error) {
console.log('请求失败', error)
}
}
const getType = async () => {
try {
const result = await API({
url: '/dou/getType'
})
typeList.value = result.data
} catch (error) {
console.log('请求失败', error)
}
}
const handlePageSizeChange = (val) => {
getObj.value.pageSize = val
getObj.value.pageNum = 1
getInit({})
}
const handleCurrentChange = function (val) {
getObj.value.pageNum = val
getInit({})
}
const platformList = ref<string[]>([
// 'stripe',
// 'ios',
// 'FirstData',
// 'paymentasia',
// 'system',
// '金币系统'
])
const typeList = ref<string[]>([
'金币换金豆',
'金币换免费金豆',
'赠送金豆',
'购买金豆',
'客服操作'
])
//搜索表单数据
const detailY = ref({
jwcode: '',
deptName: '',
orderNo: '',
payStyle: '',
type: '',
startTime:'',
endTime:''
})
const getObj = ref({
pageNum: 1,
pageSize: 50
})
// const exportExcel = function () {
// dialogVisible.value = true
// isExport.value = true
// }
// const exportConfirm = function () {
// if (excelData.timegap == '1') {
// excelData.startTime = moment().startOf('day').format('YYYY-MM-DD HH:mm:ss')
// excelData.endTime = moment().endOf('day').format('YYYY-MM-DD HH:mm:ss')
// } else if (excelData.timegap == '3') {
// excelData.startTime = moment()
// .subtract(3, 'days')
// .startOf('day')
// .format('YYYY-MM-DD HH:mm:ss')
// excelData.endTime = moment().endOf('day').format('YYYY-MM-DD HH:mm:ss')
// } else if (excelData.timegap == '7') {
// excelData.startTime = moment()
// .subtract(7, 'days')
// .startOf('day')
// .format('YYYY-MM-DD')
// excelData.endTime = moment().endOf('day').format('YYYY-MM-DD HH:mm:ss')
// } else if (excelData.timegap == '30') {
// excelData.startTime = moment()
// .subtract(30, 'days')
// .startOf('day')
// .format('YYYY-MM-DD HH:mm:ss')
// excelData.endTime = moment().endOf('day').format('YYYY-MM-DD HH:mm:ss')
// }
// getInit(
// {
// sortField: '',
// sortOrder: ''
// },
// (data) => {
// console.log('导出数据', data)
// //导出的数据将字段映射
// data = data.map((item) => {
// return {
// 姓名: item.name,
// 精网号: item.jwcode,
// 地区: item.deptName,
// 订单号: item.orderNo,
// 充值平台: item.payStyle,
// 金豆数量: item.count,
// 充值时间: moment(item.successTime).format('YYYY-MM-DD'),
// 金额: item.price
// }
// })
// if (data.length == 0) {
// ElMessage.error('没有数据')
// isExport.value = false
// dialogVisible.value = false
// return
// }
// console.log('导出数据', data)
// excelExport(data)
// }
// )
// }
//数据导出excel
// const excelExport = async function (data) {
// const worksheet = utils.json_to_sheet(data)
// const workbook = utils.book_new()
// utils.book_append_sheet(workbook, worksheet, 'Sheet1')
// const wbout = write(workbook, { bookType: 'xlsx', type: 'array' })
// saveAs(
// new Blob([wbout], { type: 'application/octet-stream' }),
// '数据导出.xlsx'
// )
// isExport.value = false
// dialogVisible.value = false
// }
const ruleFormRef = ref<FormInstance>()
//初始化
const getInit = async function (
{
sortField = '',
sortOrder = ''
}: {
sortField?: string
sortOrder?: string
},
// callback?: Function
) {
try {
console.log('搜索参数', getObj.value)
const startTime = detailY.value.startTime
const endTime = detailY.value.endTime
console.log(startTime, endTime)
// 发送POST请求
const result = await API({
url: '/dou/getPay',
data: {
pay: {
jwcode: detailY.value.jwcode,
deptName: detailY.value.deptName,
startTime: detailY.value.startTime || '',
endTime: detailY.value.endTime || '',
payStyle: detailY.value.payStyle,
type: detailY.value.type,
orderNo: detailY.value.orderNo,
sortField,
sortOrder
},
pageNum: getObj.value.pageNum,
pageSize: getObj.value.pageSize
}
})
// if (isExport.value) {
// !!callback && callback(result.data)
// } else {
tableData.value = result.data.list
total.value = result.data.total
// }
} catch (error) {
console.log('请求失败', error)
// 在这里可以处理错误逻辑,比如显示错误提示等
}
}
const handleSortChange = (column) => {
const { prop, order } = column
if (order === 'ascending') {
getInit({ sortField: prop, sortOrder: 'ASC' })
} else if (order === 'descending') {
getInit({ sortField: prop, sortOrder: 'DESC' })
}
}
// 精网号、订单号、充值类型去空格
const trim = () => {
if (detailY.value.jwcode) {
detailY.value.jwcode = detailY.value.jwcode.replace(/\s/g, '');
}
if (detailY.value.orderNo) {
detailY.value.orderNo = detailY.value.orderNo.replace(/\s/g, '');
}
if (detailY.value.type) {
detailY.value.type = detailY.value.type.replace(/\s/g, '');
}
}
// 搜索
const search = function () {
trim();
getObj.value.pageNum = 1
getInit({})
getCount()
}
// 重置
const reset = function (formEl) {
formEl.resetFields()
}
//获取支付方式接口
const getPayType = async () => {
try {
const result = await API({
url: '/dou/getStyle'
})
platformList.value = result.data
// typeList.value = result.data
} catch (error) {
console.log('请求失败', error)
}
}
//获取金豆数接口
const getCount = async () => {
try {
const result = await API({
url: '/dou/getTotal',
data: {
jwcode: detailY.value.jwcode,
deptName: detailY.value.deptName,
startTime: detailY.value.startTime,
endTime: detailY.value.endTime,
orderNo: detailY.value.orderNo,
type: detailY.value.type
// payStyle: detailY.value.payStyle
}
})
if (!!result.data) {
const { price, count } = result.data
console.log('金豆总数', price, count)
priceValue.value = price
countValue.value = count
} else {
priceValue.value = 0
countValue.value = 0
}
} catch (error) {
console.log('请求失败', error)
}
}
onMounted(() => {
getInit({})
getPayType()
getCount()
getArea()
getType()
})
</script>
<style scoped lang="scss">
.filter-box {
width: 100%;
display: flex;
justify-content: space-between;
align-items: center;
padding: 20px;
padding-bottom: 0px;
box-sizing: border-box;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
margin-bottom: 20px;
border-radius: 5px;
.el-form {
display: flex;
flex-wrap: wrap;
row-gap: 20px;
column-gap: 20px;
}
}
.table-box {
width: 100%;
padding: 20px;
box-sizing: border-box;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
border-radius: 5px;
}
.pagination {
display: flex;
align-items: center;
margin-top: 10px;
}
.filter-box {
width: 100%;
display: flex;
justify-content: space-between;
align-items: center;
padding: 20px;
padding-bottom: 0px;
box-sizing: border-box;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
margin-bottom: 20px;
border-radius: 5px;
.el-form {
display: flex;
flex-wrap: wrap;
row-gap: 20px;
column-gap: 20px;
}
}
.table-box {
width: 100%;
padding: 20px;
box-sizing: border-box;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
border-radius: 5px;
}
.pagination {
display: flex;
align-items: center;
margin-top: 10px;
}
</style>