比赛
All checks were successful
Deploy to Server / deploy (push) Successful in 36s

This commit is contained in:
jeremygan2021
2026-03-10 13:32:04 +08:00
parent 3ada996915
commit af763b1bee
7 changed files with 447 additions and 31 deletions

View File

@@ -1,12 +1,15 @@
import { View, Text, Button, Image, ScrollView, RichText } from '@tarojs/components'
import { View, Text, Button, Image, ScrollView } from '@tarojs/components'
import Taro, { useLoad } from '@tarojs/taro'
import { useState } from 'react'
import { getCompetitionDetail, enrollCompetition, getMyCompetitionEnrollment } from '../../api'
import { getCompetitionDetail, enrollCompetition, getMyCompetitionEnrollment, getProjects } from '../../api'
import MarkdownReader from '../../components/MarkdownReader'
import './detail.scss'
export default function CompetitionDetail() {
const [detail, setDetail] = useState<any>(null)
const [enrollment, setEnrollment] = useState<any>(null)
const [projects, setProjects] = useState<any[]>([])
const [activeTab, setActiveTab] = useState(0)
const [loading, setLoading] = useState(false)
useLoad((options) => {
@@ -14,6 +17,7 @@ export default function CompetitionDetail() {
if (id) {
fetchDetail(id)
fetchEnrollment(id)
fetchProjects(id)
}
})
@@ -38,6 +42,17 @@ export default function CompetitionDetail() {
}
}
const fetchProjects = async (id) => {
try {
const res = await getProjects({ competition: id, status: 'submitted' })
// 如果后端返回了分页结果 { results: [], ... },则取 results否则直接取 res
const list = res.results || res
setProjects(Array.isArray(list) ? list : [])
} catch (e) {
console.error('Fetch projects failed', e)
}
}
const handleEnroll = async () => {
if (!detail) return
try {
@@ -75,20 +90,83 @@ export default function CompetitionDetail() {
<Text className={`status ${detail.status}`}>{getStatusText(detail.status)}</Text>
</View>
<View className='section'>
<Text className='section-title'></Text>
<RichText nodes={detail.description} />
<View className='tabs'>
{['详情', '参赛项目', '排行榜'].map((tab, index) => (
<View
key={index}
className={`tab-item ${activeTab === index ? 'active' : ''}`}
onClick={() => setActiveTab(index)}
>
{tab}
</View>
))}
</View>
<View className='section'>
<Text className='section-title'></Text>
<RichText nodes={detail.rule_description} />
</View>
{activeTab === 0 && (
<>
<View className='section'>
<Text className='section-title'></Text>
<MarkdownReader content={detail.description} />
</View>
<View className='section'>
<Text className='section-title'></Text>
<RichText nodes={detail.condition_description} />
</View>
<View className='section'>
<Text className='section-title'></Text>
<MarkdownReader content={detail.rule_description} />
</View>
<View className='section'>
<Text className='section-title'></Text>
<MarkdownReader content={detail.condition_description} />
</View>
</>
)}
{activeTab === 1 && (
<View className='project-list'>
{projects.map(project => (
<View className='project-card' key={project.id}>
<Image
className='cover'
mode='aspectFill'
src={project.display_cover_image || 'https://via.placeholder.com/120x90'}
/>
<View className='info'>
<Text className='title'>{project.title}</Text>
<View className='author'>
<View className='user'>
<Image className='avatar' src={project.contestant_info?.avatar_url || ''} />
<Text>{project.contestant_info?.nickname || '参赛者'}</Text>
</View>
{project.final_score > 0 && <Text className='score'>{project.final_score}</Text>}
</View>
</View>
</View>
))}
{projects.length === 0 && <View className='empty'></View>}
</View>
)}
{activeTab === 2 && (
<View className='ranking-list'>
{projects
.filter(p => p.final_score > 0)
.sort((a, b) => b.final_score - a.final_score)
.map((project, index) => (
<View className='rank-item' key={project.id}>
<Text className={`rank-num top${index + 1}`}>{index + 1}</Text>
<View className='info'>
<Image className='avatar' src={project.contestant_info?.avatar_url || ''} />
<View className='detail'>
<Text className='nickname'>{project.contestant_info?.nickname || '参赛者'}</Text>
<Text className='project-title'>{project.title}</Text>
</View>
</View>
<Text className='score'>{project.final_score}</Text>
</View>
))}
{projects.filter(p => p.final_score > 0).length === 0 && <View className='empty'></View>}
</View>
)}
</View>
<View className='footer-action'>