<template>
|
<div class="review-container">
|
<!-- 页面标题区域 -->
|
<div class="page-header">
|
<div class="title-section">
|
<h1 class="page-title">项目评审</h1>
|
<p class="page-subtitle">管理比赛项目的评审流程,查看评分结果和项目详情</p>
|
</div>
|
|
</div>
|
|
<!-- 搜索工具栏 -->
|
<div class="search-toolbar">
|
<div class="search-form">
|
<el-input
|
v-model="searchName"
|
placeholder="请输入项目名称"
|
@keyup.enter="loadProjects"
|
@clear="handleClear"
|
style="width: 180px"
|
clearable
|
/>
|
<el-select
|
v-model="selectedActivity"
|
placeholder="请选择比赛"
|
@change="handleActivityChange"
|
style="width: 200px"
|
clearable
|
filterable
|
>
|
<template #prefix>
|
<el-icon><Trophy /></el-icon>
|
</template>
|
<el-option
|
v-for="activity in activities"
|
:key="activity.id"
|
:label="getActivityDisplayName(activity)"
|
:value="activity.id"
|
>
|
<span>{{ getActivityName(activity) }}</span>
|
<span v-if="activity.pid > 0" style="color: #409eff; margin-left: 8px;">
|
{{ activity.name }}
|
</span>
|
</el-option>
|
</el-select>
|
<el-button
|
type="primary"
|
:icon="Search"
|
@click="loadProjects"
|
:loading="projectsLoading"
|
>
|
查询
|
</el-button>
|
</div>
|
</div>
|
|
<el-table
|
:data="projects"
|
style="width: 100%"
|
v-loading="projectsLoading"
|
empty-text="请先选择比赛"
|
>
|
<el-table-column prop="playerName" label="项目名称" min-width="150">
|
<template #default="scope">
|
{{ scope.row.projectName || scope.row.playerName }}
|
</template>
|
</el-table-column>
|
<el-table-column prop="playerName" label="参赛人姓名" min-width="120" />
|
<el-table-column prop="phone" label="联系电话" min-width="120" />
|
<el-table-column prop="ratingCount" label="评审次数" width="100" align="center">
|
<template #default="scope">
|
<el-tag :type="scope.row.ratingCount > 0 ? 'success' : 'info'">
|
{{ scope.row.ratingCount }}
|
</el-tag>
|
</template>
|
</el-table-column>
|
<el-table-column prop="averageScore" label="平均分" width="100" align="center">
|
<template #default="scope">
|
<span v-if="scope.row.averageScore > 0" class="score">
|
{{ scope.row.averageScore.toFixed(1) }}
|
</span>
|
<span v-else class="no-score">未评分</span>
|
</template>
|
</el-table-column>
|
<el-table-column prop="applyTime" label="报名时间" width="180">
|
<template #default="scope">
|
{{ formatDate(scope.row.applyTime) }}
|
</template>
|
</el-table-column>
|
<el-table-column prop="reviewStatus" label="评审状态" width="100" align="center">
|
<template #default="scope">
|
<el-tag :type="getReviewStatusType(scope.row.ratingCount)">
|
{{ getReviewStatusName(scope.row.ratingCount) }}
|
</el-tag>
|
</template>
|
</el-table-column>
|
<el-table-column label="操作" width="80" align="center">
|
<template #default="scope">
|
<el-button
|
text
|
:icon="View"
|
@click="viewDetails(scope.row.id)"
|
class="action-btn view-btn"
|
title="详情评审"
|
/>
|
</template>
|
</el-table-column>
|
</el-table>
|
|
<!-- 分页 -->
|
<div class="pagination-container" v-if="total > 0">
|
<el-pagination
|
v-model:current-page="currentPage"
|
v-model:page-size="pageSize"
|
:page-sizes="[10, 20, 50, 100]"
|
:total="total"
|
layout="total, sizes, prev, pager, next, jumper"
|
@size-change="handleSizeChange"
|
@current-change="handleCurrentChange"
|
/>
|
</div>
|
</div>
|
</template>
|
|
<script setup>
|
import { ref, onMounted } from 'vue'
|
import { useRouter } from 'vue-router'
|
import { ElMessage } from 'element-plus'
|
import { Search, Trophy, View } from '@element-plus/icons-vue'
|
import { getActiveActivities, getRatingStats } from '@/api/projectReview'
|
import { getProjectReviewApplications } from '@/api/projectReviewNew'
|
|
const router = useRouter()
|
|
// 响应式数据
|
const activities = ref([])
|
const selectedActivity = ref(null)
|
const projects = ref([])
|
const searchName = ref('')
|
const activitiesLoading = ref(false)
|
const projectsLoading = ref(false)
|
|
// 分页数据
|
const currentPage = ref(1)
|
const pageSize = ref(10)
|
const total = ref(0)
|
|
// 加载比赛列表
|
const loadActivities = async () => {
|
console.log('=== 开始加载比赛列表 ===')
|
activitiesLoading.value = true
|
try {
|
console.log('调用 getActiveActivities...')
|
const data = await getActiveActivities()
|
console.log('getActiveActivities 返回数据:', data)
|
activities.value = data
|
console.log('activities.value 设置为:', activities.value)
|
console.log('activities.value.length:', activities.value?.length)
|
} catch (error) {
|
console.error('加载比赛列表失败:', error)
|
ElMessage.error(error.message)
|
} finally {
|
activitiesLoading.value = false
|
console.log('=== 比赛列表加载完成 ===')
|
}
|
}
|
|
// 加载项目列表
|
const loadProjects = async () => {
|
if (!selectedActivity.value) {
|
ElMessage.warning('请先选择比赛')
|
return
|
}
|
|
console.log('=== 开始加载项目列表 ===')
|
console.log('selectedActivity.value:', selectedActivity.value)
|
console.log('currentPage.value:', currentPage.value)
|
console.log('pageSize.value:', pageSize.value)
|
|
projectsLoading.value = true
|
try {
|
const params = {
|
activityId: selectedActivity.value,
|
page: currentPage.value,
|
size: pageSize.value
|
}
|
|
// 如果有搜索名称,添加到参数中
|
if (searchName.value && searchName.value.trim()) {
|
params.name = searchName.value.trim()
|
}
|
|
console.log('API调用参数:', params)
|
|
const response = await getProjectReviewApplications(params)
|
console.log('API响应:', response)
|
|
// 处理响应数据 - 新的分页结构
|
const pageData = response.projectReviewApplications
|
projects.value = pageData?.content || []
|
total.value = pageData?.totalElements || 0
|
|
console.log('设置 projects.value:', projects.value)
|
console.log('projects.value.length:', projects.value.length)
|
console.log('设置 total.value:', total.value)
|
} catch (error) {
|
console.error('加载项目列表失败:', error)
|
ElMessage.error('加载项目列表失败')
|
// 如果API调用失败,显示空数据
|
projects.value = []
|
total.value = 0
|
} finally {
|
projectsLoading.value = false
|
}
|
}
|
|
// 处理比赛选择变化
|
const handleActivityChange = (activityId) => {
|
currentPage.value = 1
|
loadProjects()
|
}
|
|
// 清空搜索
|
const handleClear = () => {
|
searchName.value = ''
|
currentPage.value = 1
|
if (selectedActivity.value) {
|
loadProjects()
|
}
|
}
|
|
// 重置搜索
|
const resetSearch = () => {
|
searchName.value = ''
|
selectedActivity.value = null
|
currentPage.value = 1
|
projects.value = []
|
total.value = 0
|
}
|
|
// 分页处理
|
const handleSizeChange = (size) => {
|
pageSize.value = size
|
currentPage.value = 1
|
loadProjects()
|
}
|
|
const handleCurrentChange = (page) => {
|
currentPage.value = page
|
loadProjects()
|
}
|
|
// 查看详情
|
const viewDetails = (projectId) => {
|
router.push(`/project-review/${projectId}/detail`)
|
}
|
|
// 格式化日期
|
const formatDate = (dateString) => {
|
if (!dateString) return '-'
|
return new Date(dateString).toLocaleString('zh-CN')
|
}
|
|
// 获取状态类型
|
const getStateType = (state) => {
|
const stateMap = {
|
0: 'danger', // 已拒绝
|
1: 'warning', // 待审核
|
2: 'success', // 已通过
|
3: 'info' // 已结束
|
}
|
return stateMap[state] || 'info'
|
}
|
|
// 获取状态名称
|
const getStateName = (state) => {
|
const stateMap = {
|
0: '已拒绝',
|
1: '待评审',
|
2: '已通过',
|
3: '已结束'
|
}
|
return stateMap[state] || '未知'
|
}
|
|
// 获取评审状态类型(基于评审次数)
|
const getReviewStatusType = (ratingCount) => {
|
return ratingCount > 0 ? 'success' : 'warning'
|
}
|
|
// 获取评审状态名称(基于评审次数)
|
const getReviewStatusName = (ratingCount) => {
|
return ratingCount > 0 ? '已评审' : '未评审'
|
}
|
|
// 获取比赛名称(如果是阶段,返回父比赛名称;如果是比赛,返回自己的名称)
|
const getActivityName = (activity) => {
|
if (activity.pid > 0 && activity.parent) {
|
return activity.parent.name
|
}
|
return activity.name
|
}
|
|
// 获取活动显示名称(用于搜索和选中时显示)
|
const getActivityDisplayName = (activity) => {
|
if (activity.pid > 0 && activity.parent) {
|
return `${activity.parent.name} - ${activity.name}`
|
}
|
return activity.name
|
}
|
|
// 获取阶段名称(如果是阶段,返回阶段名称;如果是比赛,返回比赛名称)
|
const getStageName = (activity) => {
|
return activity.name
|
}
|
|
|
|
// 组件挂载时加载数据
|
onMounted(() => {
|
loadActivities()
|
})
|
</script>
|
|
<style scoped>
|
.review-container {
|
padding: 20px;
|
}
|
|
/* 页面标题区域 */
|
.page-header {
|
margin-bottom: 24px;
|
}
|
|
.title-section {
|
text-align: left;
|
}
|
|
.page-title {
|
font-size: 24px;
|
font-weight: 600;
|
color: #1f2937;
|
margin: 0 0 8px 0;
|
}
|
|
.page-subtitle {
|
font-size: 14px;
|
color: #6b7280;
|
margin: 0;
|
line-height: 1.5;
|
}
|
|
/* 搜索工具栏 */
|
.search-toolbar {
|
display: flex;
|
justify-content: flex-end;
|
margin-bottom: 20px;
|
}
|
|
.search-form {
|
display: flex;
|
gap: 12px;
|
align-items: center;
|
}
|
|
.search-area {
|
display: flex;
|
align-items: center;
|
gap: 12px;
|
}
|
|
/* 操作按钮样式 */
|
.action-btn {
|
padding: 8px !important;
|
margin: 0 6px;
|
border-radius: 6px;
|
transition: all 0.2s ease;
|
}
|
|
.view-btn {
|
color: #3b82f6 !important;
|
}
|
|
.view-btn:hover {
|
background-color: rgba(59, 130, 246, 0.1) !important;
|
transform: scale(1.2);
|
}
|
|
.score {
|
color: #67c23a;
|
font-weight: 600;
|
}
|
|
.no-score {
|
color: #909399;
|
font-style: italic;
|
}
|
|
.pagination-container {
|
margin-top: 20px;
|
display: flex;
|
justify-content: center;
|
}
|
|
:deep(.el-table) {
|
border-radius: 4px;
|
}
|
|
:deep(.el-table th) {
|
background-color: #fafafa;
|
}
|
|
:deep(.el-tag) {
|
border-radius: 12px;
|
}
|
|
/* 响应式适配 */
|
@media (max-width: 768px) {
|
.search-toolbar {
|
flex-direction: column;
|
gap: 12px;
|
align-items: stretch;
|
}
|
|
.search-area {
|
justify-content: center;
|
flex-wrap: wrap;
|
}
|
}
|
</style>
|