This commit is contained in:
@@ -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'>
|
||||
|
||||
Reference in New Issue
Block a user