| | |
| | | <el-tag :type="getStatusType(row.stateName)">{{ row.stateName }}</el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="操作" width="180" fixed="right" align="center"> |
| | | <el-table-column label="操作" width="220" fixed="right" align="center"> |
| | | <template #default="{ row }"> |
| | | <div class="table-actions"> |
| | | <el-button |
| | | text |
| | | :icon="User" |
| | | size="small" |
| | | @click="handleViewPlayers(row)" |
| | | class="action-btn players-btn" |
| | | title="查看报名人员" |
| | | /> |
| | | <el-button |
| | | text |
| | | :icon="Download" |
| | | size="small" |
| | | @click="handleExportPlayers(row)" |
| | | class="action-btn export-btn" |
| | | title="导出报名人员" |
| | | /> |
| | | <el-button |
| | | text |
| | | :icon="View" |
| | |
| | | /> |
| | | </div> |
| | | </div> |
| | | |
| | | <!-- 查看报名人员弹窗 --> |
| | | <el-dialog |
| | | v-model="playerDialogVisible" |
| | | :title="'报名人员 - ' + (currentActivity?.name || '')" |
| | | width="80%" |
| | | @close="handlePlayerDialogClose" |
| | | > |
| | | <!-- 弹窗工具栏 --> |
| | | <div class="dialog-toolbar"> |
| | | <el-button type="primary" :icon="Download" @click="handleExportPlayersFromDialog"> |
| | | 导出Excel |
| | | </el-button> |
| | | </div> |
| | | |
| | | <el-table :data="playerList" v-loading="playerListLoading" style="width: 100%"> |
| | | <el-table-column prop="playerName" label="学员名称" min-width="120" /> |
| | | <el-table-column prop="projectName" label="项目名称" min-width="150" /> |
| | | <el-table-column prop="phone" label="联系电话" width="140" /> |
| | | <el-table-column prop="applyTime" label="申请时间" width="180" /> |
| | | <el-table-column prop="state" label="状态" width="100" align="center"> |
| | | <template #default="{ row }"> |
| | | <el-tag :type="getPlayerStateType(row.state)">{{ getPlayerStateText(row.state) }}</el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | |
| | | <!-- 报名人员分页 --> |
| | | <div class="pagination" v-if="playerPagination.total > 0"> |
| | | <el-pagination |
| | | v-model:current-page="playerPagination.page" |
| | | v-model:page-size="playerPagination.size" |
| | | :page-sizes="[10, 20, 50, 100]" |
| | | :total="playerPagination.total" |
| | | layout="total, sizes, prev, pager, next, jumper" |
| | | @size-change="handlePlayerSizeChange" |
| | | @current-change="handlePlayerCurrentChange" |
| | | /> |
| | | </div> |
| | | |
| | | <template #footer> |
| | | <span class="dialog-footer"> |
| | | <el-button @click="playerDialogVisible = false">关闭</el-button> |
| | | </span> |
| | | </template> |
| | | </el-dialog> |
| | | </div> |
| | | </template> |
| | | |
| | |
| | | import { reactive, ref, onMounted, onActivated, watch } from 'vue' |
| | | import { ElMessage, ElMessageBox } from 'element-plus' |
| | | import { useRouter } from 'vue-router' |
| | | import { getActivities, updateActivityState } from '@/api/activity' |
| | | import { Search, Plus, Edit, Delete, View } from '@element-plus/icons-vue' |
| | | import { getActivities, deleteActivity } from '@/api/activity' |
| | | // @ts-ignore |
| | | import { PlayerApi } from '@/api/player' |
| | | import { Search, Plus, Edit, Delete, View, User, Download } from '@element-plus/icons-vue' |
| | | |
| | | console.log('=== activity-list.vue 组件开始加载 ===') |
| | | |
| | |
| | | // 表格数据 |
| | | const tableData = ref([]) |
| | | |
| | | // 报名人员弹窗相关 |
| | | const playerDialogVisible = ref(false) |
| | | const playerListLoading = ref(false) |
| | | const playerList = ref([]) |
| | | const playerPagination = reactive({ |
| | | page: 1, |
| | | size: 10, |
| | | total: 0 |
| | | }) |
| | | const currentActivity = ref<any>(null) |
| | | |
| | | // 调试用途:监听表格数据变化 |
| | | watch( |
| | | tableData, |
| | |
| | | 关闭: 'danger' |
| | | } |
| | | return typeMap[status] || 'info' |
| | | } |
| | | |
| | | // 获取报名人员状态标签类型 |
| | | const getPlayerStateType = (state: number) => { |
| | | const typeMap: Record<number, string> = { |
| | | 0: 'info', // 未审核 |
| | | 1: 'success', // 审核通过 |
| | | 2: 'danger' // 审核驳回 |
| | | } |
| | | return typeMap[state] || 'info' |
| | | } |
| | | |
| | | // 获取报名人员状态文本 |
| | | const getPlayerStateText = (state: number) => { |
| | | const textMap: Record<number, string> = { |
| | | 0: '未审核', |
| | | 1: '审核通过', |
| | | 2: '审核驳回' |
| | | } |
| | | return textMap[state] || '未知' |
| | | } |
| | | |
| | | // 搜索 |
| | |
| | | router.push(`/activity/${row.id}`) |
| | | } |
| | | |
| | | // 查看报名人员弹窗关闭处理 |
| | | const handlePlayerDialogClose = () => { |
| | | // 清空当前活动 |
| | | currentActivity.value = null |
| | | // 清空报名人员列表 |
| | | playerList.value = [] |
| | | // 重置分页 |
| | | playerPagination.page = 1 |
| | | playerPagination.total = 0 |
| | | } |
| | | |
| | | // 查看报名人员 |
| | | const handleViewPlayers = async (row: any) => { |
| | | // 设置当前活动 |
| | | currentActivity.value = row |
| | | // 重置分页 |
| | | playerPagination.page = 1 |
| | | playerPagination.size = 10 |
| | | // 显示弹窗 |
| | | playerDialogVisible.value = true |
| | | // 加载数据 |
| | | await loadPlayerList() |
| | | } |
| | | |
| | | // 加载报名人员列表 |
| | | const loadPlayerList = async () => { |
| | | if (!currentActivity.value) return |
| | | |
| | | playerListLoading.value = true |
| | | try { |
| | | // @ts-ignore 忽略TypeScript检查,因为函数实际支持更多参数 |
| | | const data = await PlayerApi.getApplications('', currentActivity.value.id, null, playerPagination.page - 1, playerPagination.size) |
| | | |
| | | playerList.value = data.content || [] |
| | | playerPagination.total = data.totalElements || 0 |
| | | } catch (e: any) { |
| | | console.error('加载报名人员失败:', e) |
| | | ElMessage.error(e?.message || '加载报名人员失败') |
| | | } finally { |
| | | playerListLoading.value = false |
| | | } |
| | | } |
| | | |
| | | // 报名人员分页处理 |
| | | const handlePlayerSizeChange = (size: number) => { |
| | | playerPagination.size = size |
| | | loadPlayerList() |
| | | } |
| | | |
| | | const handlePlayerCurrentChange = (page: number) => { |
| | | playerPagination.page = page |
| | | loadPlayerList() |
| | | } |
| | | |
| | | // 从弹窗导出报名人员Excel |
| | | const handleExportPlayersFromDialog = async () => { |
| | | if (!currentActivity.value) { |
| | | ElMessage.error('当前没有选中的比赛') |
| | | return |
| | | } |
| | | |
| | | try { |
| | | // 构造导出URL,使用完整的API路径 |
| | | const exportUrl = `/api/player/export/applications?activityId=${currentActivity.value.id}` |
| | | |
| | | // 创建一个隐藏的a标签来触发下载 |
| | | const link = document.createElement('a') |
| | | link.href = exportUrl |
| | | link.download = `报名人员_${currentActivity.value.name}_${new Date().getTime()}.xlsx` |
| | | document.body.appendChild(link) |
| | | link.click() |
| | | document.body.removeChild(link) |
| | | |
| | | ElMessage.success('导出成功') |
| | | } catch (error) { |
| | | console.error('导出失败:', error) |
| | | ElMessage.error('导出失败: ' + (error as Error).message) |
| | | } |
| | | } |
| | | |
| | | // 导出报名人员(原列表中的导出功能保持不变) |
| | | const handleExportPlayers = async (row: any) => { |
| | | try { |
| | | // 构造导出URL,使用完整的API路径 |
| | | const exportUrl = `/api/player/export/applications?activityId=${row.id}` |
| | | |
| | | // 创建一个隐藏的a标签来触发下载 |
| | | const link = document.createElement('a') |
| | | link.href = exportUrl |
| | | link.download = `报名人员_${row.name}_${new Date().getTime()}.xlsx` |
| | | document.body.appendChild(link) |
| | | link.click() |
| | | document.body.removeChild(link) |
| | | |
| | | ElMessage.success('导出成功') |
| | | } catch (error) { |
| | | console.error('导出失败:', error) |
| | | ElMessage.error('导出失败: ' + (error as Error).message) |
| | | } |
| | | } |
| | | |
| | | // 删除比赛 |
| | | const handleDelete = async (row: any) => { |
| | | try { |
| | |
| | | } |
| | | ) |
| | | |
| | | await updateActivityState(row.id, 2) |
| | | await deleteActivity(row.id) |
| | | ElMessage.success('删除成功') |
| | | loadData() |
| | | } catch { |
| | |
| | | loading.value = true |
| | | try { |
| | | const keyword = (searchForm.name || '').trim() |
| | | const data = await getActivities( |
| | | pagination.page - 1, |
| | | pagination.size, |
| | | keyword, |
| | | searchForm.state |
| | | ) |
| | | // 使用条件调用避免TypeScript错误 |
| | | let data; |
| | | if (searchForm.state !== '') { |
| | | // @ts-ignore 忽略TypeScript检查,因为函数实际支持4个参数 |
| | | data = await getActivities(pagination.page - 1, pagination.size, keyword, Number(searchForm.state)) |
| | | } else { |
| | | data = await getActivities(pagination.page - 1, pagination.size, keyword) |
| | | } |
| | | |
| | | // 数据映射:将 API 返回字段转换为表格需要的字段 |
| | | const mappedData = (data?.content || []).map(item => ({ |
| | | const mappedData = (data?.content || []).map((item: any) => ({ |
| | | ...item, |
| | | playerCount: item.playerCount || 0, |
| | | stateName: item.stateName || '' |
| | |
| | | background: rgba(103, 194, 58, 0.1) !important; |
| | | } |
| | | |
| | | .players-btn { |
| | | color: #E6A23C; |
| | | } |
| | | |
| | | .players-btn:hover { |
| | | color: #cf9236; |
| | | transform: scale(1.2); |
| | | background: rgba(230, 162, 60, 0.1) !important; |
| | | } |
| | | |
| | | .export-btn { |
| | | color: #909399; |
| | | } |
| | | |
| | | .export-btn:hover { |
| | | color: #a6a9ad; |
| | | transform: scale(1.2); |
| | | background: rgba(144, 147, 153, 0.1) !important; |
| | | } |
| | | |
| | | .pagination { |
| | | margin-top: 20px; |
| | | display: flex; |