97054a9699
- user 端:课程/活动/报名/测评/政策/调研 - 后端已并入 server-core/app/training,/api/* 走 opc.pinesound.cn
81 lines
3.8 KiB
React
81 lines
3.8 KiB
React
import React from 'react';
|
||
import { ContentTemplate } from '@/components/templates';
|
||
import { SectionHead, Button, Icon } from '@/components/atoms';
|
||
import { Reveal } from '@/components/organisms';
|
||
import Skeleton from '@/components/Skeleton';
|
||
import { getBookableEvents } from '@/services/booking';
|
||
import '@/styles/booking.css';
|
||
|
||
const fmtEvt = (iso) => {
|
||
if (!iso) return '';
|
||
const d = new Date(iso);
|
||
const p = (n) => String(n).padStart(2, '0');
|
||
const week = ['日', '一', '二', '三', '四', '五', '六'][d.getDay()];
|
||
return `${d.getMonth() + 1}月${d.getDate()}日 周${week} ${p(d.getHours())}:${p(d.getMinutes())}`;
|
||
};
|
||
|
||
export default function Events() {
|
||
const [list, setList] = React.useState([]);
|
||
const [loaded, setLoaded] = React.useState(false);
|
||
React.useEffect(() => { getBookableEvents().then((l) => { setList(l); setLoaded(true); }); }, []);
|
||
const SkeletonCard = () => (
|
||
<div className="bk-ev-card">
|
||
<Skeleton.Box h={190} />
|
||
<div className="bk-ev-body" style={{ padding: '14px 16px' }}>
|
||
<Skeleton.Line w="70%" h={18} />
|
||
<Skeleton.Line w="100%" h={12} style={{ marginTop: 10 }} />
|
||
<Skeleton.Line w="45%" h={12} style={{ marginTop: 8 }} />
|
||
</div>
|
||
</div>
|
||
);
|
||
|
||
return (
|
||
<ContentTemplate
|
||
active="events"
|
||
kicker="Events"
|
||
title="活动 · 公益课与沙龙"
|
||
desc="线下与线上活动按主题排期,公益课每周 1 场、交流沙龙每月 2–4 场。选择一期主题,进入详情报名。"
|
||
>
|
||
<div className="ev-grid">
|
||
{list.map((e) => {
|
||
const STATUS_TEXT = { open: '报名中', full: '已满员', done: '已结束', pending: '待开放', invite: '邀请中' };
|
||
const ST_CLS = { full: ' full', done: ' done', pending: ' pending', invite: ' invite' };
|
||
const status = STATUS_TEXT[e.status] || '报名中';
|
||
const st = ST_CLS[e.status] || '';
|
||
return (
|
||
<Reveal as="div" className="bk-ev-card" key={e.id}>
|
||
<div className="bk-ev-poster">
|
||
{e.image ? <img className="bk-ev-img" src={e.image} alt={e.title} /> : <div className="bk-ev-img ph">{e.title}</div>}
|
||
<div className="bk-ev-tags">
|
||
<span className={`bk-ev-tag${e.type === 'salon' ? ' alt' : ''}`}>{e.type === 'salon' ? '沙龙' : '公益课'}</span>
|
||
<span className="bk-ev-tag mode">{e.mode === 'online' ? '线上' : '线下'}</span>
|
||
</div>
|
||
</div>
|
||
<div className="bk-ev-body">
|
||
<div className="bk-ev-title">{e.title}</div>
|
||
<div className="bk-ev-sub">{e.subtitle || e.desc}</div>
|
||
<div className="bk-ev-meta">
|
||
<div className="bk-ev-line"><Icon name="clock" size="sm" /> <span>{fmtEvt(e.startAt)}</span></div>
|
||
<div className="bk-ev-line"><Icon name="map-pin" size="sm" /> <span>{e.location}</span></div>
|
||
{e.showCapacity && e.capacity > 0 && (
|
||
<div className="bk-ev-line"><Icon name="users" size="sm" /> <span>名额 {e.enrolled || 0} / {e.capacity}</span></div>
|
||
)}
|
||
</div>
|
||
<div className="bk-ev-foot">
|
||
<span className="bk-ev-price">免费</span>
|
||
<span className={`bk-ev-status${st}`}>{status}</span>
|
||
</div>
|
||
</div>
|
||
<div className="bk-ev-cta">
|
||
<Button variant="cta" href={`#/event-detail?id=${e.id}`}>查看详情 / 报名 <Icon name="arrow-right" size="sm" /></Button>
|
||
</div>
|
||
</Reveal>
|
||
);
|
||
})}
|
||
{!loaded && Array.from({ length: 3 }).map((_, i) => <SkeletonCard key={i} />)}
|
||
{loaded && list.length === 0 && <div className="bk-empty">暂无可报名活动,请稍后再来。</div>}
|
||
</div>
|
||
</ContentTemplate>
|
||
);
|
||
}
|