<template>
|
<div class="judge-page">
|
<!-- 页面标题区域 -->
|
<div class="page-header">
|
<div class="title-section">
|
<h1 class="page-title">评委管理</h1>
|
<p class="page-subtitle">管理比赛评委信息,包括评委的基本信息和专业背景</p>
|
</div>
|
</div>
|
|
<!-- 搜索工具栏 -->
|
<div class="search-toolbar">
|
<el-input
|
v-model="searchQuery"
|
placeholder="搜索评委..."
|
style="width: 200px"
|
clearable
|
@clear="handleClear"
|
/>
|
<el-button type="primary" @click="handleSearch">
|
<el-icon><Search /></el-icon>
|
查询
|
</el-button>
|
<el-button type="primary" @click="openAddDialog">
|
<el-icon><Plus /></el-icon>
|
新增评委
|
</el-button>
|
</div>
|
|
<el-table :data="judges" style="width: 100%; margin-top: 20px" v-loading="loading">
|
<!-- 头像列 - 第一列 -->
|
<el-table-column label="头像" width="80" align="center">
|
<template #default="scope">
|
<el-avatar
|
v-if="scope.row.avatarUrl"
|
:src="scope.row.avatarUrl"
|
:size="40"
|
/>
|
<el-avatar
|
v-else
|
:size="40"
|
:style="{ backgroundColor: getAvatarColor(scope.row.name) }"
|
>
|
{{ scope.row.name?.charAt(0) || '?' }}
|
</el-avatar>
|
</template>
|
</el-table-column>
|
|
<!-- 姓名列 -->
|
<el-table-column prop="name" label="姓名" width="120" />
|
|
<!-- 电话列 -->
|
<el-table-column prop="phone" label="电话" width="150" />
|
|
<!-- 简介列 -->
|
<el-table-column prop="description" label="简介" min-width="200" show-overflow-tooltip />
|
|
<!-- 操作列 -->
|
<el-table-column label="操作" width="120" align="center">
|
<template #default="scope">
|
<el-button
|
text
|
:icon="Edit"
|
@click="editJudge(scope.row)"
|
class="action-btn edit-btn"
|
title="编辑"
|
/>
|
<el-button
|
text
|
:icon="Delete"
|
@click="deleteJudge(scope.row.id)"
|
class="action-btn delete-btn"
|
title="删除"
|
/>
|
</template>
|
</el-table-column>
|
</el-table>
|
|
<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"
|
style="margin-top: 20px; justify-content: center"
|
@size-change="handleSizeChange"
|
@current-change="handleCurrentChange"
|
/>
|
|
<!-- 新增/编辑对话框 -->
|
<JudgeFormSimple
|
v-model="dialogVisible"
|
:judge-data="currentJudge"
|
@success="handleFormSuccess"
|
/>
|
</div>
|
</template>
|
|
<script setup lang="ts">
|
import { ref, onMounted } from 'vue'
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
import { Plus, Search, Edit, Delete } from '@element-plus/icons-vue'
|
import JudgeFormSimple from '@/components/JudgeFormSimple.vue'
|
import { JudgeApi } from '@/api/judge'
|
|
interface Judge {
|
id: string
|
name: string
|
phone: string
|
email: string
|
organization: string
|
title: string
|
avatar?: string
|
}
|
|
const judges = ref<Judge[]>([])
|
const searchQuery = ref('')
|
const currentPage = ref(1)
|
const pageSize = ref(10)
|
const total = ref(0)
|
const dialogVisible = ref(false)
|
const currentJudge = ref<Judge | null>(null)
|
const loading = ref(false)
|
|
const loadJudges = async () => {
|
try {
|
loading.value = true
|
let judgeList = []
|
if (searchQuery.value) {
|
judgeList = await JudgeApi.searchJudges(searchQuery.value)
|
} else {
|
judgeList = await JudgeApi.getJudges()
|
}
|
|
// 简单的分页处理(实际项目中应该在后端实现)
|
const startIndex = (currentPage.value - 1) * pageSize.value
|
const endIndex = startIndex + pageSize.value
|
judges.value = judgeList.slice(startIndex, endIndex)
|
total.value = judgeList.length
|
} catch (error) {
|
ElMessage.error('加载评委列表失败')
|
console.error(error)
|
} finally {
|
loading.value = false
|
}
|
}
|
|
const handleSearch = () => {
|
currentPage.value = 1
|
loadJudges()
|
}
|
|
const handleClear = () => {
|
searchQuery.value = ''
|
currentPage.value = 1
|
loadJudges()
|
}
|
|
const handleSizeChange = (val: number) => {
|
pageSize.value = val
|
loadJudges()
|
}
|
|
const handleCurrentChange = (val: number) => {
|
currentPage.value = val
|
loadJudges()
|
}
|
|
const openAddDialog = () => {
|
currentJudge.value = null
|
dialogVisible.value = true
|
}
|
|
const editJudge = async (judge: Judge) => {
|
try {
|
// 调用API获取完整的Judge详情数据
|
const judgeDetail = await JudgeApi.getJudge(judge.id)
|
if (judgeDetail) {
|
currentJudge.value = judgeDetail
|
dialogVisible.value = true
|
} else {
|
ElMessage.error('获取评委详情失败')
|
}
|
} catch (error) {
|
ElMessage.error('获取评委详情失败')
|
console.error(error)
|
}
|
}
|
|
const deleteJudge = async (id: string) => {
|
try {
|
await ElMessageBox.confirm('确定要删除这个评委吗?', '提示', {
|
confirmButtonText: '确定',
|
cancelButtonText: '取消',
|
type: 'warning'
|
})
|
|
await JudgeApi.deleteJudge(id)
|
ElMessage.success('删除成功')
|
loadJudges()
|
} catch (error) {
|
if (error !== 'cancel') {
|
ElMessage.error('删除失败')
|
console.error(error)
|
}
|
}
|
}
|
|
const handleFormSuccess = () => {
|
dialogVisible.value = false
|
loadJudges()
|
}
|
|
// 根据名称生成头像背景色
|
const getAvatarColor = (name: string): string => {
|
if (!name) return '#909399'
|
|
// 预定义的美观颜色数组
|
const colors = [
|
'#409EFF', // 蓝色
|
'#67C23A', // 绿色
|
'#E6A23C', // 橙色
|
'#F56C6C', // 红色
|
'#909399', // 灰色
|
'#9C27B0', // 紫色
|
'#FF9800', // 深橙色
|
'#4CAF50', // 深绿色
|
'#2196F3', // 深蓝色
|
'#FF5722', // 深红色
|
'#795548', // 棕色
|
'#607D8B' // 蓝灰色
|
]
|
|
// 根据名称字符串生成固定的索引
|
let hash = 0
|
for (let i = 0; i < name.length; i++) {
|
hash = name.charCodeAt(i) + ((hash << 5) - hash)
|
}
|
|
// 确保索引在颜色数组范围内
|
const index = Math.abs(hash) % colors.length
|
return colors[index]
|
}
|
|
onMounted(() => {
|
loadJudges()
|
})
|
</script>
|
|
<style lang="scss" scoped>
|
.judge-page {
|
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;
|
align-items: center;
|
justify-content: space-between;
|
margin-bottom: 20px;
|
padding: 16px;
|
background-color: #f9fafb;
|
border-radius: 8px;
|
border: 1px solid #e5e7eb;
|
}
|
|
.search-area {
|
display: flex;
|
align-items: center;
|
gap: 12px;
|
}
|
|
/* 搜索工具栏样式 */
|
.search-toolbar {
|
display: flex;
|
gap: 12px;
|
align-items: center;
|
justify-content: flex-end;
|
margin-bottom: 20px;
|
}
|
|
/* 搜索按钮 */
|
.search-btn {
|
width: 24px !important;
|
height: 24px !important;
|
min-height: 24px !important;
|
padding: 0 !important;
|
margin-right: 8px;
|
}
|
|
/* 操作按钮样式 */
|
.action-btn {
|
padding: 8px !important;
|
margin: 0 6px;
|
border-radius: 6px;
|
transition: all 0.2s ease;
|
}
|
|
.edit-btn {
|
color: #3b82f6 !important;
|
}
|
|
.edit-btn:hover {
|
background-color: rgba(59, 130, 246, 0.1) !important;
|
transform: scale(1.2);
|
}
|
|
.delete-btn {
|
color: #ef4444 !important;
|
}
|
|
.delete-btn:hover {
|
background-color: rgba(239, 68, 68, 0.1) !important;
|
transform: scale(1.2);
|
}
|
|
.el-pagination {
|
display: flex;
|
justify-content: center;
|
}
|
|
/* 响应式适配 */
|
@media (max-width: 768px) {
|
.search-toolbar {
|
flex-direction: column;
|
gap: 12px;
|
align-items: stretch;
|
}
|
|
.search-area {
|
justify-content: center;
|
}
|
}
|
</style>
|