This commit is contained in:
96
frontend/src/components/competition/CompetitionCard.jsx
Normal file
96
frontend/src/components/competition/CompetitionCard.jsx
Normal file
@@ -0,0 +1,96 @@
|
||||
import React from 'react';
|
||||
import { Card, Tag, Typography, Space, Divider } from 'antd';
|
||||
import { CalendarOutlined } from '@ant-design/icons';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import dayjs from 'dayjs';
|
||||
import ReactMarkdown from 'react-markdown';
|
||||
|
||||
const { Title } = Typography;
|
||||
|
||||
const CompetitionCard = ({ competition }) => {
|
||||
const navigate = useNavigate();
|
||||
|
||||
const getStatusColor = (status) => {
|
||||
switch(status) {
|
||||
case 'published': return 'cyan';
|
||||
case 'registration': return 'green';
|
||||
case 'submission': return 'blue';
|
||||
case 'judging': return 'orange';
|
||||
case 'ended': return 'red';
|
||||
default: return 'default';
|
||||
}
|
||||
};
|
||||
|
||||
const getStatusText = (status) => {
|
||||
switch(status) {
|
||||
case 'published': return '即将开始';
|
||||
case 'registration': return '报名中';
|
||||
case 'submission': return '作品提交中';
|
||||
case 'judging': return '评审中';
|
||||
case 'ended': return '已结束';
|
||||
default: return '草稿';
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Card
|
||||
hoverable
|
||||
cover={
|
||||
<div style={{ height: 280, overflow: 'hidden', position: 'relative' }}>
|
||||
<img
|
||||
alt={competition.title}
|
||||
src={competition.display_cover_image || 'https://images.unsplash.com/photo-1556761175-5973dc0f32e7?w=400&h=280&fit=crop'}
|
||||
style={{ width: '100%', height: '100%', objectFit: 'cover' }}
|
||||
/>
|
||||
<div style={{ position: 'absolute', top: 10, right: 10 }}>
|
||||
<Tag color={getStatusColor(competition.status)} style={{ marginRight: 0, fontSize: 14, padding: '4px 12px' }}>
|
||||
{getStatusText(competition.status)}
|
||||
</Tag>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
style={{ height: '100%', display: 'flex', flexDirection: 'column', fontSize: 16 }}
|
||||
bodyStyle={{ flex: 1, display: 'flex', flexDirection: 'column', padding: 24 }}
|
||||
onClick={() => navigate(`/competitions/${competition.id}`)}
|
||||
>
|
||||
<Title level={3} ellipsis={{ rows: 2 }} style={{ marginBottom: 12, height: 64, fontSize: 20 }}>
|
||||
{competition.title}
|
||||
</Title>
|
||||
|
||||
<div style={{
|
||||
flex: 1,
|
||||
color: 'rgba(255,255,255,0.65)',
|
||||
overflow: 'hidden',
|
||||
display: '-webkit-box',
|
||||
WebkitLineClamp: 3,
|
||||
WebkitBoxOrient: 'vertical',
|
||||
marginBottom: 0,
|
||||
fontSize: '15px',
|
||||
lineHeight: 1.6
|
||||
}}>
|
||||
<ReactMarkdown
|
||||
allowedElements={['p', 'text', 'strong', 'em', 'del']}
|
||||
unwrapDisallowed={true}
|
||||
components={{
|
||||
p: (props) => <span {...props} />,
|
||||
}}
|
||||
>
|
||||
{competition.description}
|
||||
</ReactMarkdown>
|
||||
</div>
|
||||
|
||||
<Divider style={{ margin: '12px 0' }} />
|
||||
|
||||
<Space direction="vertical" style={{ width: '100%' }} size={8}>
|
||||
<Space>
|
||||
<CalendarOutlined style={{ color: '#1890ff', fontSize: 16 }} />
|
||||
<span style={{ fontSize: 14 }}>
|
||||
{dayjs(competition.start_time).format('YYYY-MM-DD')} ~ {dayjs(competition.end_time).format('YYYY-MM-DD')}
|
||||
</span>
|
||||
</Space>
|
||||
</Space>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
export default CompetitionCard;
|
||||
Reference in New Issue
Block a user