238 lines
9.2 KiB
Vue
238 lines
9.2 KiB
Vue
<template>
|
||
<div class="punishment">
|
||
<ClubScopeHint />
|
||
<div class="type-switch">
|
||
<el-radio-group v-model="activeType" size="large" @change="onTypeChange">
|
||
<el-radio-button value="jifen">积分处罚</el-radio-button>
|
||
<el-radio-button value="fakuan">罚款审核</el-radio-button>
|
||
</el-radio-group>
|
||
</div>
|
||
|
||
<!-- ==================== 积分处罚(原有功能,完全不变) ==================== -->
|
||
<template v-if="activeType === 'jifen'">
|
||
<!-- 顶部统计卡片 -->
|
||
<el-row :gutter="20" class="stats-cards">
|
||
<el-col :xs="24" :sm="8" :md="8" :lg="8" :xl="8">
|
||
<el-card class="stat-card" shadow="hover">
|
||
<div class="stat-item">
|
||
<div class="stat-label">总记录</div>
|
||
<div class="stat-value">{{ stats.zongshu || 0 }}</div>
|
||
</div>
|
||
</el-card>
|
||
</el-col>
|
||
<el-col :xs="24" :sm="8" :md="8" :lg="8" :xl="8">
|
||
<el-card class="stat-card" shadow="hover" @click="switchStatusTab('pending')">
|
||
<div class="stat-item">
|
||
<div class="stat-label">待处理</div>
|
||
<div class="stat-value warning">{{ stats.daichuli || 0 }}</div>
|
||
</div>
|
||
</el-card>
|
||
</el-col>
|
||
<el-col :xs="24" :sm="8" :md="8" :lg="8" :xl="8">
|
||
<el-card class="stat-card" shadow="hover" @click="switchStatusTab('processed')">
|
||
<div class="stat-item">
|
||
<div class="stat-label">已处理</div>
|
||
<div class="stat-value success">{{ stats.yichuli || 0 }}</div>
|
||
</div>
|
||
</el-card>
|
||
</el-col>
|
||
</el-row>
|
||
|
||
<!-- 筛选区域 -->
|
||
<el-card class="filter-card" shadow="hover">
|
||
<el-row :gutter="20">
|
||
<el-col :xs="24" :sm="8" :md="8" :lg="8" :xl="8">
|
||
<el-input v-model="filters.dingdan_id" placeholder="订单ID" clearable @keyup.enter="handleSearch" />
|
||
</el-col>
|
||
<el-col :xs="24" :sm="8" :md="8" :lg="8" :xl="8">
|
||
<el-input v-model="filters.dashouid" placeholder="打手ID" clearable @keyup.enter="handleSearch" />
|
||
</el-col>
|
||
<el-col :xs="24" :sm="8" :md="8" :lg="8" :xl="8" class="filter-actions">
|
||
<el-button type="primary" @click="handleSearch" :loading="loading">搜索</el-button>
|
||
<el-button @click="resetFilters">重置</el-button>
|
||
<el-button :icon="Refresh" @click="refreshList" circle />
|
||
</el-col>
|
||
</el-row>
|
||
|
||
<el-tabs v-model="activeStatus" class="status-tabs" @tab-change="handleStatusChange">
|
||
<el-tab-pane label="全部" name="all" />
|
||
<el-tab-pane label="待处理" name="pending" />
|
||
<el-tab-pane label="已处理" name="processed" />
|
||
</el-tabs>
|
||
</el-card>
|
||
|
||
<!-- 处罚记录表格 -->
|
||
<el-card class="table-card" shadow="hover">
|
||
<el-table :data="list" v-loading="loading" border stripe style="width: 100%" @row-click="goToDetail">
|
||
<el-table-column prop="dingdan_id" label="订单ID" width="180" />
|
||
<el-table-column prop="dashouid" label="打手ID" width="120" />
|
||
<el-table-column prop="qingqiuid" label="请求人ID" width="120" />
|
||
<el-table-column prop="cfliyou" label="处罚理由" min-width="200" show-overflow-tooltip />
|
||
<el-table-column label="状态" width="100">
|
||
<template #default="{ row }">
|
||
<el-tag :type="getStatusType(row.sqzhuangtai)">{{ getStatusText(row.sqzhuangtai) }}</el-tag>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="create_time" label="创建时间" width="160" :formatter="formatTime" />
|
||
<el-table-column label="操作" width="100" fixed="right">
|
||
<template #default="{ row }">
|
||
<el-button type="primary" link @click.stop="goToDetail(row)">详情</el-button>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
|
||
<div class="pagination">
|
||
<el-pagination
|
||
v-model:current-page="page"
|
||
v-model:page-size="pageSize"
|
||
:page-sizes="[10, 20, 30, 50]"
|
||
:total="total"
|
||
layout="total, sizes, prev, pager, next, jumper"
|
||
@size-change="handleSizeChange"
|
||
@current-change="handlePageChange"
|
||
/>
|
||
</div>
|
||
</el-card>
|
||
</template>
|
||
|
||
<!-- ==================== 罚款审核模块(新组件) ==================== -->
|
||
<FadanManagement v-if="activeType === 'fakuan'" />
|
||
</div>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { ref, reactive, onMounted } from 'vue'
|
||
import { useRouter } from 'vue-router'
|
||
import { ElMessage } from 'element-plus'
|
||
import { Refresh } from '@element-plus/icons-vue'
|
||
import request from '@/utils/request'
|
||
import { JITUAN_API } from '@/utils/club-context'
|
||
import ClubScopeHint from '@/components/ClubScopeHint.vue'
|
||
import FadanManagement from '@/views/punishment/components/FadanManagement.vue'
|
||
|
||
const router = useRouter()
|
||
|
||
// 当前选中的类型:jifen / fakuan
|
||
const activeType = ref('jifen')
|
||
|
||
// ==================== 积分处罚相关数据(保持原样) ====================
|
||
const loading = ref(false)
|
||
const list = ref([])
|
||
const total = ref(0)
|
||
const page = ref(1)
|
||
const pageSize = ref(20)
|
||
|
||
const stats = ref({ zongshu: 0, daichuli: 0, yichuli: 0 })
|
||
|
||
const filters = reactive({ dingdan_id: '', dashouid: '' })
|
||
const activeStatus = ref('all')
|
||
|
||
const getStatusArray = () => {
|
||
if (activeStatus.value === 'all') return undefined
|
||
if (activeStatus.value === 'pending') return [0, 3]
|
||
return [1, 2]
|
||
}
|
||
|
||
const fetchData = async () => {
|
||
loading.value = true
|
||
try {
|
||
const params = {
|
||
phone: localStorage.getItem('username'),
|
||
page: page.value,
|
||
page_size: pageSize.value,
|
||
dingdan_id: filters.dingdan_id || undefined,
|
||
dashouid: filters.dashouid || undefined
|
||
}
|
||
const statusArr = getStatusArray()
|
||
if (statusArr) params.status = statusArr
|
||
Object.keys(params).forEach(key => params[key] === undefined && delete params[key])
|
||
const res = await request.post(JITUAN_API.kefuCfgl, params)
|
||
if (res.code === 0) {
|
||
const data = res.data
|
||
list.value = (data.list || []).map((item) => ({
|
||
...item,
|
||
create_time: item.create_time || item.CreateTime || '',
|
||
update_time: item.update_time || item.UpdateTime || '',
|
||
}))
|
||
total.value = data.total || 0
|
||
stats.value = {
|
||
zongshu: data.stats?.zongshu || 0,
|
||
daichuli: data.stats?.daichuli || 0,
|
||
yichuli: data.stats?.yichuli || 0
|
||
}
|
||
} else {
|
||
ElMessage.error(res.msg || '获取失败')
|
||
}
|
||
} catch (error) {
|
||
console.error(error)
|
||
ElMessage.error('获取失败')
|
||
} finally {
|
||
loading.value = false
|
||
}
|
||
}
|
||
|
||
const handleSearch = () => { page.value = 1; fetchData() }
|
||
const resetFilters = () => { filters.dingdan_id = ''; filters.dashouid = ''; handleSearch() }
|
||
const refreshList = () => fetchData()
|
||
const handleStatusChange = () => { page.value = 1; fetchData() }
|
||
const switchStatusTab = (tab) => {
|
||
const map = { pending: 'pending', processed: 'processed' }
|
||
const next = map[tab]
|
||
if (!next || activeStatus.value === next) return
|
||
activeStatus.value = next
|
||
handleStatusChange()
|
||
}
|
||
const handleSizeChange = (val) => { pageSize.value = val; page.value = 1; fetchData() }
|
||
const handlePageChange = (val) => { page.value = val; fetchData() }
|
||
|
||
const goToDetail = (row) => {
|
||
router.push(`/punishment/detail/${row.dingdan_id}`)
|
||
}
|
||
|
||
const formatTime = (row, column, cellValue) => {
|
||
if (!cellValue) return '--'
|
||
const date = new Date(cellValue)
|
||
return `${date.getFullYear()}-${(date.getMonth()+1).toString().padStart(2,'0')}-${date.getDate().toString().padStart(2,'0')} ${date.getHours().toString().padStart(2,'0')}:${date.getMinutes().toString().padStart(2,'0')}`
|
||
}
|
||
|
||
const getStatusText = (status) => {
|
||
return { 0: '待处理', 1: '已处罚', 2: '已驳回', 3: '申诉中' }[status] || '未知'
|
||
}
|
||
const getStatusType = (status) => {
|
||
if (status === 0 || status === 3) return 'warning'
|
||
if (status === 1) return 'success'
|
||
if (status === 2) return 'info'
|
||
return ''
|
||
}
|
||
|
||
const onTypeChange = (val) => {
|
||
if (val === 'jifen') fetchData()
|
||
}
|
||
|
||
onMounted(() => {
|
||
if (activeType.value === 'jifen') fetchData()
|
||
})
|
||
</script>
|
||
|
||
<style scoped>
|
||
.punishment { padding: 20px; background-color: #f5f9fc; min-height: 100%; }
|
||
.type-switch { margin-bottom: 20px; text-align: center; }
|
||
.stats-cards { margin-bottom: 20px; }
|
||
.stat-card { border-radius: 12px; transition: transform 0.2s; cursor: pointer; }
|
||
.stat-card:hover { transform: translateY(-2px); box-shadow: 0 8px 16px rgba(0,0,0,0.05); }
|
||
.stat-item { text-align: center; padding: 10px 0; }
|
||
.stat-label { font-size: 14px; color: #6b7a88; margin-bottom: 8px; }
|
||
.stat-value { font-size: 32px; font-weight: 600; color: #1a2634; }
|
||
.stat-value.warning { color: #e6a23c; }
|
||
.stat-value.success { color: #67c23a; }
|
||
.filter-card { margin-bottom: 20px; border-radius: 12px; }
|
||
.filter-actions { display: flex; gap: 12px; align-items: center; flex-wrap: wrap; }
|
||
.status-tabs { margin-top: 16px; }
|
||
.table-card { border-radius: 12px; }
|
||
.pagination { margin-top: 20px; display: flex; justify-content: flex-end; }
|
||
@media screen and (max-width: 768px) {
|
||
.punishment { padding: 12px; }
|
||
.filter-actions { margin-top: 12px; justify-content: flex-start; }
|
||
.pagination { justify-content: center; }
|
||
}
|
||
</style> |