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.
409 lines
13 KiB
409 lines
13 KiB
<template>
|
|
<el-row>
|
|
<el-col>
|
|
<div>
|
|
<el-card style="margin-bottom: 5px">
|
|
<el-row style="margin-bottom: 5px">
|
|
<el-col :span="6">
|
|
<el-text size="large">精网号:</el-text>
|
|
<el-input v-model="searchForm.jwcode" placeholder="请输入精网号" style="width: 240px" clearable />
|
|
</el-col>
|
|
<el-col :span="6">
|
|
<el-text size="large">退款类型:</el-text>
|
|
<el-select v-model="searchForm.refundType" placeholder="请选择" style="width: 240px" clearable>
|
|
<el-option label="商品退款" value="商品退款" />
|
|
<el-option label="退点啥??" value="退点啥??" />
|
|
</el-select>
|
|
</el-col>
|
|
<el-col :span="6">
|
|
<el-text size="large">所属地区:</el-text>
|
|
<el-select v-model="searchForm.area" placeholder="请选择" style="width: 240px" clearable>
|
|
<el-option v-for="item in areaOptions" :key="item" :label="item" :value="item" />
|
|
</el-select>
|
|
</el-col>
|
|
</el-row>
|
|
<el-row>
|
|
<el-col :span="12">
|
|
<el-text size="large">退款时间:</el-text>
|
|
<el-date-picker v-model="dateRange" type="datetimerange" range-separator="至" start-placeholder="开始日期"
|
|
end-placeholder="结束日期" style="width: 400px" />
|
|
<el-button @click="getToday()" style="margin-left: 10px">今</el-button>
|
|
<el-button @click="getYesterday()" style="margin-left: 10px">昨</el-button>
|
|
<el-button @click="get7Days()" style="margin-left: 10px">近7天</el-button>
|
|
</el-col>
|
|
<el-col :span="6">
|
|
<el-button type="success" @click="resetSearch">重置</el-button>
|
|
<el-button type="primary" @click="handleSearch">查询</el-button>
|
|
</el-col>
|
|
</el-row>
|
|
</el-card>
|
|
</div>
|
|
</el-col>
|
|
</el-row>
|
|
|
|
<el-card>
|
|
<el-tabs v-model="checkTab" @tab-change="switchTab">
|
|
<el-tab-pane label="待审核" name="1" />
|
|
<el-tab-pane label="已通过" name="2" />
|
|
<el-tab-pane label="已驳回" name="3" />
|
|
</el-tabs>
|
|
|
|
<div class="stats-info">
|
|
退款记录条数: {{ stats.totalItems }}
|
|
退款金币总数: {{ stats.totalCoins }}
|
|
永久金币: {{ stats.permanentCoins }}
|
|
免费金币: {{ stats.freeCoins }}
|
|
任务金币: {{ stats.taskCoins }}
|
|
</div>
|
|
|
|
<el-table :data="tableData" height="540px" @sort-change="handleSortChange">
|
|
<el-table-column type="index" label="序号" width="60" />
|
|
<el-table-column prop="username" label="姓名" width="120" />
|
|
<el-table-column prop="jwcode" label="精网号" width="120" />
|
|
<el-table-column prop="area" label="所属地区" width="120" />
|
|
<el-table-column prop="refundType" label="退款类型" width="120" />
|
|
<el-table-column prop="refundMethod" label="退款方式" width="120" />
|
|
<el-table-column prop="refundGoods" label="退款商品" width="120" />
|
|
<el-table-column prop="refundAmount" label="退款金额" width="120" sortable="custom">
|
|
<template #default="{ row }">
|
|
{{ row.rechargeCoin + row.freeCoin + row.taskCoin }}
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column prop="rechargeCoin" label="永久金币" width="120" sortable="custom" />
|
|
<el-table-column prop="freeCoin" label="免费金币" width="120" sortable="custom" />
|
|
<el-table-column prop="taskCoin" label="任务金币" width="120" sortable="custom" />
|
|
<el-table-column prop="remark" label="备注" width="150" show-overflow-tooltip /><!-- 当内容过长被隐藏时显示 tooltip -->
|
|
<el-table-column prop="adminName" label="提交人" width="120" />
|
|
<el-table-column v-if="checkTab === 'rejected'" prop="reason" label="驳回理由" width="150" show-overflow-tooltip />
|
|
<el-table-column v-if="checkTab !== 'pending'" prop="auditName" label="审核人" width="120" />
|
|
<el-table-column prop="createTime" label="提交时间" width="180" sortable="custom">
|
|
<template #default="{ row }">
|
|
{{ moment(row.createTime).format('YYYY-MM-DD HH:mm:ss') }}
|
|
</template>
|
|
</el-table-column>
|
|
|
|
<el-table-column v-if="checkTab !== 'pending'" prop="auditTime" label="审核时间" width="180" sortable="custom">
|
|
<template #default="{ row }">
|
|
{{ row.auditTime ? moment(row.auditTime).format('YYYY-MM-DD HH:mm:ss') : '--' }}
|
|
</template>
|
|
</el-table-column>
|
|
|
|
<el-table-column label="操作" width="150" fixed="right" v-if="checkTab === 'pending'">
|
|
<template #default="{ row }">
|
|
<el-button type="success" size="small" @click="handleAction('approve', row)">通过</el-button>
|
|
<el-button type="danger" size="small" @click="handleAction('reject', row)">驳回</el-button>
|
|
</template>
|
|
</el-table-column>
|
|
</el-table>
|
|
|
|
<el-pagination v-model:current-page="pagination.pageNum" v-model:page-size="pagination.pageSize"
|
|
:total="pagination.total" :page-sizes="[10, 20, 50, 100]" layout="total, sizes, prev, pager, next, jumper"
|
|
@size-change="handlePagination('size', $event)" @current-change="handlePagination('page', $event)"
|
|
class="pagination" />
|
|
</el-card>
|
|
|
|
<!-- 驳回弹出框 -->
|
|
<el-dialog v-model="rejectDialog" title="驳回理由" width="500px">
|
|
<el-form :model="rejectForm">
|
|
<el-form-item label="驳回理由">
|
|
<el-input v-model="rejectForm.reason" type="textarea" :rows="4" placeholder="请输入驳回理由" maxlength="200"
|
|
show-word-limit />
|
|
</el-form-item>
|
|
</el-form>
|
|
<template #footer>
|
|
<el-button @click="rejectDialog=false">取消</el-button>
|
|
<el-button type="primary" @click="rejectRefund">确定</el-button>
|
|
</template>
|
|
</el-dialog>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { ref, onMounted } from 'vue'
|
|
import request from '@/util/http'
|
|
import { ElMessage } from 'element-plus'
|
|
import moment from 'moment'
|
|
|
|
// 状态常量
|
|
const STATUS = {
|
|
PENDING: 0,// 待审核
|
|
APPROVED: 1,// 通过
|
|
REJECTED: 2 // 驳回
|
|
}
|
|
|
|
// 搜索表单
|
|
const searchForm = ref({
|
|
jwcode: '',
|
|
refundType: '',
|
|
refundGoods: '',
|
|
area: '',
|
|
startTime: '',
|
|
endTime: ''
|
|
})
|
|
|
|
const checkTab = ref(1) // 能否不用STATUS常量,1是待审批,2是已通过,3是驳回,参数status需要Integer
|
|
const dateRange = ref([])
|
|
|
|
const pagination = ref({
|
|
pageNum: 1,
|
|
pageSize: 50,
|
|
total: 0
|
|
})
|
|
|
|
const tableData = ref([])
|
|
const productOptions = ref([])
|
|
const areaOptions = ref([])
|
|
const adminInfo = ref({})
|
|
const stats = ref({
|
|
totalItems: 0,
|
|
totalCoins: 0,
|
|
permanentCoins: 0,
|
|
freeCoins: 0,
|
|
taskCoins: 0
|
|
})
|
|
// 驳回
|
|
const rejectDialog = ref(false) // 驳回对话框
|
|
const rejectForm = ref({ reason: '' })
|
|
const currentRecord = ref(null)
|
|
// 获取用户信息
|
|
const fetchAdminInfo = async () => {
|
|
try {
|
|
const res = await request({ url: '/admin/userinfo' })
|
|
adminInfo.value = res
|
|
if (res.area !== '总部') {
|
|
searchForm.value.area = res.area
|
|
}
|
|
} catch (error) {
|
|
console.error('获取用户信息失败', error)
|
|
}
|
|
}
|
|
|
|
// 查商品
|
|
const fetchProducts = async () => {
|
|
try {
|
|
const res = await request({ url: '/product' })
|
|
productOptions.value = res.data || []
|
|
} catch (error) {
|
|
console.error('获取商品列表失败', error)
|
|
}
|
|
}
|
|
|
|
// 查地区
|
|
const fetchAreas = async () => {
|
|
try {
|
|
const result = await request({ url: 'http://18.143.76.3:10704/general/market' })
|
|
areaOptions.value = result.data || []
|
|
} catch (error) {
|
|
console.error('获取地区列表失败', error)
|
|
}
|
|
}
|
|
|
|
const get = async () => {
|
|
console.log('===========================================' + checkTab.value)
|
|
try {
|
|
const params = {
|
|
pageNum: pagination.value.pageNum,
|
|
pageSize: pagination.value.pageSize,
|
|
detail: {
|
|
...searchForm.value,
|
|
status: getCurrentStatus()
|
|
}
|
|
}
|
|
// 时间格式化
|
|
if (dateRange.value?.length === 2) {
|
|
params.detail.startTime = moment(dateRange.value[0]).format('YYYY-MM-DD HH:mm:ss')
|
|
params.detail.endTime = moment(dateRange.value[1]).format('YYYY-MM-DD HH:mm:ss')
|
|
}
|
|
|
|
const res = await request({
|
|
url: '/audit/audit/refund',
|
|
data: params
|
|
})
|
|
|
|
tableData.value = res.data?.list || []
|
|
pagination.value.total = res.data?.total || 0
|
|
|
|
fetchStats()
|
|
} catch (error) {
|
|
console.error('获取数据失败', error)
|
|
}
|
|
}
|
|
|
|
const fetchStats = async () => {
|
|
try {
|
|
const params = { ...searchForm.value, status: getCurrentStatus() }
|
|
const res = await request({
|
|
url: '/refund/RefundA',
|
|
data: params
|
|
})
|
|
|
|
if (res.data) {
|
|
const data = res.data
|
|
stats.value = {
|
|
totalItems: data.raudit || 0,
|
|
totalCoins: data.sumRaudit || 0,
|
|
permanentCoins: data.permanentCoins || 0,
|
|
freeCoins: data.freeCoins || 0,
|
|
taskCoins: data.taskCoins || 0
|
|
}
|
|
}
|
|
} catch (error) {
|
|
console.error('获取统计信息失败', error)
|
|
}
|
|
}
|
|
|
|
const handleSearch = () => {
|
|
pagination.value.pageNum = 1
|
|
get()
|
|
}
|
|
|
|
const resetSearch = () => {
|
|
searchForm.value = {
|
|
jwcode: '',
|
|
refundType: '',
|
|
refundGoods: '',
|
|
area: adminInfo.value.area === '总部' ? '' : adminInfo.value.area,
|
|
startTime: '',
|
|
endTime: ''
|
|
}
|
|
dateRange.value = []
|
|
handleSearch()
|
|
}
|
|
|
|
// 转换格式 moment(param).format('YYYY-MM-DD HH:mm:ss')
|
|
// 今天
|
|
const getToday = () => {
|
|
const today = new Date()
|
|
const start = moment(new Date(today.getFullYear(), today.getMonth(), today.getDate(), 0, 0, 0)).format('YYYY-MM-DD HH:mm:ss')
|
|
const end = moment(new Date(today.getFullYear(), today.getMonth(), today.getDate() + 1, 0, 0, 0)).format('YYYY-MM-DD HH:mm:ss')
|
|
dateRange.value = [start, end]
|
|
get()
|
|
}
|
|
|
|
// 昨天
|
|
const getYesterday = () => {
|
|
const yesterday = new Date()
|
|
yesterday.setDate(yesterday.getDate() - 1)
|
|
const start = new Date(yesterday.getFullYear(), yesterday.getMonth(), yesterday.getDate(), 0, 0, 0)
|
|
const end = new Date(yesterday.getFullYear(), yesterday.getMonth(), yesterday.getDate() + 1, 0, 0, 0)
|
|
dateRange.value = [moment(start).format('YYYY-MM-DD HH:mm:ss'), moment(end).format('YYYY-MM-DD HH:mm:ss')]
|
|
get()
|
|
}
|
|
|
|
// 近7天
|
|
const get7Days = () => {
|
|
const today = new Date()
|
|
const start = new Date(today.getFullYear(), today.getMonth(), today.getDate() - 6, 0, 0, 0)
|
|
const end = new Date(today.getFullYear(), today.getMonth(), today.getDate() + 1, 0, 0, 0)
|
|
dateRange.value = [start,end]// 好像不转换也可以??????
|
|
get()
|
|
}
|
|
const switchTab = (tab) => {
|
|
checkTab.value = tab
|
|
pagination.value.pageNum = 1
|
|
get()
|
|
}
|
|
|
|
// 当前状态
|
|
const getCurrentStatus = () => {
|
|
switch (checkTab.value) {
|
|
case 'pending': return STATUS.PENDING
|
|
case 'approved': return STATUS.APPROVED
|
|
case 'rejected': return STATUS.REJECTED
|
|
default: return ''
|
|
}
|
|
}
|
|
|
|
const handlePagination = (type, val) => {
|
|
if (type === 'size') {
|
|
pagination.value.pageSize = val
|
|
} else {
|
|
pagination.value.pageNum = val
|
|
}
|
|
get()
|
|
}
|
|
|
|
const handleAction = (type, row) => {
|
|
currentRecord.value = row
|
|
if (type === 'reject') {
|
|
rejectForm.value.reason = ''
|
|
rejectDialog.value = true
|
|
} else if (type === 'approve') {
|
|
approveRefund()
|
|
}
|
|
}
|
|
|
|
const approveRefund = async () => {
|
|
try {
|
|
const params = {
|
|
adminId: adminInfo.value.adminId,
|
|
auditId: currentRecord.value.auditId,
|
|
status: STATUS.APPROVED,
|
|
refundId: currentRecord.value.refundId
|
|
}
|
|
|
|
await request({
|
|
url: '/audit/audit/edit',
|
|
data: params
|
|
})
|
|
|
|
ElMessage.success('退款已批准')
|
|
get()
|
|
} catch (error) {
|
|
console.error('批准失败', error)
|
|
ElMessage.error('操作失败')
|
|
}
|
|
}
|
|
|
|
const rejectRefund = async () => {
|
|
if (!rejectForm.value.reason) {
|
|
ElMessage.warning('请输入驳回理由')
|
|
return
|
|
}
|
|
|
|
try {
|
|
const params = {
|
|
adminId: adminInfo.value.adminId,
|
|
auditId: currentRecord.value.auditId,
|
|
status: STATUS.REJECTED,
|
|
refundId: currentRecord.value.refundId,
|
|
reason: rejectForm.value.reason
|
|
}
|
|
|
|
await request({
|
|
url: '/audit/audit/edit',
|
|
data: params
|
|
})
|
|
|
|
ElMessage.success('退款已驳回')
|
|
rejectDialog.value = false
|
|
get()
|
|
} catch (error) {
|
|
console.error('驳回失败', error)
|
|
ElMessage.error('操作失败')
|
|
}
|
|
}
|
|
|
|
onMounted(async () => {
|
|
await fetchAdminInfo()// 用户信息要挂吗
|
|
|
|
await fetchProducts()
|
|
await fetchAreas()
|
|
get()
|
|
})
|
|
</script>
|
|
|
|
<style scoped>
|
|
.quickly-buttons {
|
|
margin-left: 10px;
|
|
}
|
|
|
|
.stats-info {
|
|
padding: 3px;
|
|
background-color: #f5f7fa;
|
|
}
|
|
|
|
.pagination {
|
|
margin-top: 20px;
|
|
justify-content: flex-end;
|
|
}
|
|
</style>
|