|
|
<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>
|