修正競賽團隊編輯、個人賽顯示、團體賽顯示 bug

This commit is contained in:
2025-09-20 22:44:21 +08:00
parent c5bbec5ca8
commit 049b53fa43
15 changed files with 480 additions and 85 deletions

View File

@@ -703,6 +703,7 @@ export function CompetitionManagement() {
fetchJudgeStats()
fetchTeams()
fetchTeamStats()
fetchAvailableApps()
}, [])
// 當競賽列表載入完成後,載入每個競賽的評分進度
@@ -859,11 +860,33 @@ export function CompetitionManagement() {
// Get participants based on competition type
const getParticipants = (competitionType: string) => {
console.log('🔍 getParticipants 調用:', {
competitionType,
dbTeamsLength: dbTeams.length,
teamsLength: teams.length,
isLoadingTeams
})
switch (competitionType) {
case "individual":
return mockIndividualApps
console.log('🔍 個人賽APP數據:', {
availableAppsLength: availableApps.length,
availableApps: availableApps.slice(0, 2)
})
return availableApps
case "team":
return dbTeams.length > 0 ? dbTeams : teams
// 總是使用 dbTeams如果為空則返回空數組
console.log('🔍 getParticipants 團隊數據:', {
dbTeamsLength: dbTeams.length,
dbTeams: dbTeams.slice(0, 2), // 只顯示前2個
firstTeam: dbTeams[0] ? {
id: dbTeams[0].id,
name: dbTeams[0].name,
leader_name: dbTeams[0].leader_name,
member_count: dbTeams[0].member_count,
submissionDate: dbTeams[0].submissionDate
} : null
})
return dbTeams
default:
return []
}
@@ -875,15 +898,22 @@ export function CompetitionManagement() {
let searchTerm = participantSearchTerm
let departmentFilterValue = departmentFilter
console.log('🔍 getFilteredParticipants 調用:', {
competitionType,
participantsLength: participants.length,
searchTerm,
departmentFilterValue
})
// Use separate search terms for mixed competitions
if (newCompetition.type === "mixed") {
searchTerm = competitionType === "individual" ? individualParticipantSearchTerm : teamParticipantSearchTerm
departmentFilterValue = competitionType === "individual" ? individualDepartmentFilter : teamDepartmentFilter
}
return participants.filter((participant) => {
const filtered = participants.filter((participant) => {
const searchField = competitionType === "team" ? participant.name : participant.name
const creatorField = competitionType === "team" ? participant.leader : participant.creator
const creatorField = competitionType === "team" ? (participant.leader_name || participant.leader) : (participant.creator_name || participant.creator_id || participant.creator)
const matchesSearch =
searchField.toLowerCase().includes(searchTerm.toLowerCase()) ||
@@ -891,6 +921,21 @@ export function CompetitionManagement() {
const matchesDepartment = departmentFilterValue === "all" || participant.department === departmentFilterValue
return matchesSearch && matchesDepartment
})
console.log('🔍 getFilteredParticipants 結果:', {
competitionType,
filteredLength: filtered.length,
filtered: filtered.slice(0, 2).map(f => ({
id: f.id,
name: f.name,
leader_name: f.leader_name,
leader: f.leader,
member_count: f.member_count,
submissionDate: f.submissionDate
}))
})
return filtered
}
const resetForm = () => {
@@ -2522,7 +2567,7 @@ export function CompetitionManagement() {
<TableRow key={competition.id} className={isCurrentCompetition ? "bg-purple-50" : ""}>
<TableCell>
<div className="flex items-center space-x-2">
{isCurrentCompetition && <Star className="w-4 h-4 text-purple-600 fill-current" />}
{isCurrentCompetition && <Star className="w-12 h-12 text-purple-600 fill-current" />}
<div>
<p className="font-medium">{competition.name}</p>
<p className="text-sm text-gray-500">{competition.description}</p>
@@ -3092,6 +3137,7 @@ export function CompetitionManagement() {
const matchesExpertise = judgeExpertiseFilter === "all" ||
judge.expertise.some(exp => exp.includes(judgeExpertiseFilter))
const matchesStatus = judgeStatusFilter === "all" ||
(judgeStatusFilter === "active" && judge.is_active === true) ||
(judgeStatusFilter === "inactive" && judge.is_active === false)
@@ -3124,7 +3170,7 @@ export function CompetitionManagement() {
<CardContent className="p-4">
<div className="flex items-center space-x-3 mb-3">
<Avatar>
<AvatarImage src={judge.avatar || "/placeholder.svg"} />
<AvatarImage src={judge.avatar} />
<AvatarFallback className={`${!judge.is_active ? 'bg-orange-100 text-orange-700' : 'bg-purple-100 text-purple-700'}`}>
{judge.name[0]}
</AvatarFallback>
@@ -3974,7 +4020,7 @@ export function CompetitionManagement() {
}}
/>
<Avatar className="w-8 h-8">
<AvatarImage src={judge.avatar || "/placeholder.svg"} />
<AvatarImage src={judge.avatar} />
<AvatarFallback className="bg-blue-100 text-blue-700 text-sm">
{judge.name[0]}
</AvatarFallback>
@@ -4386,7 +4432,7 @@ export function CompetitionManagement() {
}}
/>
<Avatar className="w-8 h-8">
<AvatarImage src={judge.avatar || "/placeholder.svg"} />
<AvatarImage src={judge.avatar} />
<AvatarFallback className="bg-green-100 text-green-700 text-sm">
{judge.name[0]}
</AvatarFallback>
@@ -4789,7 +4835,7 @@ export function CompetitionManagement() {
}}
/>
<Avatar className="w-8 h-8">
<AvatarImage src={judge.avatar || "/placeholder.svg"} />
<AvatarImage src={judge.avatar} />
<AvatarFallback className="bg-purple-100 text-purple-700 text-sm">
{judge.name[0]}
</AvatarFallback>
@@ -5205,8 +5251,8 @@ export function CompetitionManagement() {
{participant.department}
</Badge>
</div>
<p className="text-xs text-gray-600 mt-1">{participant.creator}</p>
<p className="text-xs text-gray-500">{participant.submissionDate || participant.created_at || '未知'}</p>
<p className="text-xs text-gray-600 mt-1">{participant.creator_name || participant.creator_id || participant.creator || '未知'}</p>
<p className="text-xs text-gray-500">{participant.submissionDate ? new Date(participant.submissionDate).toLocaleDateString('zh-TW', { timeZone: 'Asia/Taipei', year: 'numeric', month: '2-digit', day: '2-digit' }).replace(/-/g, '/') : '未知'}</p>
</div>
</div>
)
@@ -5263,8 +5309,32 @@ export function CompetitionManagement() {
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-3 max-h-64 overflow-y-auto border rounded-lg p-4 bg-white">
{getFilteredParticipants("team").map((participant) => {
{isLoadingTeams ? (
<div className="col-span-2 flex items-center justify-center py-8">
<div className="text-center">
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600 mx-auto mb-2"></div>
<p className="text-sm text-gray-600">...</p>
</div>
</div>
) : (
getFilteredParticipants("team").map((participant) => {
const isSelected = newCompetition.participatingTeams.includes(participant.id)
console.log('🔍 團隊數據調試 - 完整對象:', participant)
console.log('🔍 團隊數據調試 - 關鍵欄位:', {
name: participant.name,
leader_name: participant.leader_name,
leader: participant.leader,
member_count: participant.member_count,
submissionDate: participant.submissionDate,
hasLeaderName: 'leader_name' in participant,
hasMemberCount: 'member_count' in participant,
allKeys: Object.keys(participant)
})
console.log('🔍 渲染測試:', {
leaderDisplay: participant.leader_name || participant.leader || '未知',
memberDisplay: participant.member_count || participant.memberCount || 0,
dateDisplay: participant.submissionDate ? new Date(participant.submissionDate).toLocaleDateString('zh-TW', { timeZone: 'Asia/Taipei', year: 'numeric', month: '2-digit', day: '2-digit' }).replace(/-/g, '/') : '未知'
})
return (
<div
key={participant.id}
@@ -5318,11 +5388,12 @@ export function CompetitionManagement() {
{participant.description && (
<p className="text-xs text-gray-500 line-clamp-2">{participant.description}</p>
)}
<p className="text-xs text-gray-500">{participant.submissionDate || participant.created_at || '未知'}</p>
<p className="text-xs text-gray-500">{participant.submissionDate ? new Date(participant.submissionDate).toLocaleDateString('zh-TW', { timeZone: 'Asia/Taipei', year: 'numeric', month: '2-digit', day: '2-digit' }).replace(/-/g, '/') : '未知'}</p>
</div>
</div>
)
})}
})
)}
</div>
<div className="flex items-center justify-between p-3 bg-green-100 rounded-lg">
@@ -5432,11 +5503,11 @@ export function CompetitionManagement() {
<div className="flex items-center space-x-4 text-xs text-gray-600">
<div className="flex items-center space-x-1">
<User className="w-3 h-3" />
<span>{participant.leader}</span>
<span>{participant.leader_name || participant.leader || '未知'}</span>
</div>
<div className="flex items-center space-x-1">
<Users className="w-3 h-3" />
<span>{participant.memberCount}</span>
<span>{participant.member_count || participant.memberCount || 0}</span>
</div>
</div>
@@ -5497,10 +5568,16 @@ export function CompetitionManagement() {
{/* Individual information */}
{newCompetition.type === "individual" && (
<p className="text-xs text-gray-600 mt-1">{participant.creator}</p>
<div className="space-y-1">
<p className="text-xs text-gray-600">{participant.creator_name || participant.creator_id || participant.creator || '未知'}</p>
<p className="text-xs text-gray-500">{participant.type || participant.category || '未知'}</p>
{participant.description && (
<p className="text-xs text-gray-500 line-clamp-2">{participant.description}</p>
)}
</div>
)}
<p className="text-xs text-gray-500">{participant.submissionDate}</p>
<p className="text-xs text-gray-500">{participant.submissionDate ? new Date(participant.submissionDate).toLocaleDateString('zh-TW', { timeZone: 'Asia/Taipei', year: 'numeric', month: '2-digit', day: '2-digit' }).replace(/-/g, '/') : '未知'}</p>
</div>
</div>
)