diff --git a/pages/article/open-collaborator-award.mdx b/pages/article/open-collaborator-award.mdx
deleted file mode 100644
index 370a684..0000000
--- a/pages/article/open-collaborator-award.mdx
+++ /dev/null
@@ -1,11 +0,0 @@
-# 开放协作人奖
-
-
-
-
diff --git a/pages/article/open-collaborator-award.module.less b/pages/article/open-collaborator-award.module.less
new file mode 100644
index 0000000..a31e97d
--- /dev/null
+++ b/pages/article/open-collaborator-award.module.less
@@ -0,0 +1,532 @@
+.awardPage {
+ background: #f8f9fa;
+ min-height: 100vh;
+}
+
+// Hero 区域
+.hero {
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 50%, #f093fb 100%);
+ color: white;
+ padding: 80px 0;
+ text-align: center;
+ position: relative;
+ overflow: hidden;
+
+ &::before {
+ content: '';
+ position: absolute;
+ top: -50%;
+ left: -50%;
+ width: 200%;
+ height: 200%;
+ background: radial-gradient(circle, rgba(255, 255, 255, 0.1) 1px, transparent 1px);
+ background-size: 50px 50px;
+ animation: gridAnimation 20s linear infinite;
+ pointer-events: none;
+ }
+
+ @keyframes gridAnimation {
+ 0% {
+ transform: translate(0, 0);
+ }
+ 100% {
+ transform: translate(50px, 50px);
+ }
+ }
+}
+
+.heroTitle {
+ font-size: 56px;
+ font-weight: 700;
+ margin-bottom: 24px;
+ text-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
+ position: relative;
+ z-index: 1;
+
+ @media (max-width: 768px) {
+ font-size: 36px;
+ }
+}
+
+.heroDesc {
+ font-size: 20px;
+ margin-bottom: 48px;
+ opacity: 0.9;
+ position: relative;
+ z-index: 1;
+
+ @media (max-width: 768px) {
+ font-size: 16px;
+ }
+}
+
+.stats {
+ position: relative;
+ z-index: 1;
+ display: flex;
+ justify-content: center;
+ gap: 64px;
+
+ @media (max-width: 768px) {
+ gap: 32px;
+ }
+}
+
+.statItem {
+ text-align: center;
+}
+
+.statNumber {
+ font-size: 60px;
+ font-weight: 700;
+ margin-bottom: 8px;
+}
+
+.statLabel {
+ font-size: 16px;
+ opacity: 0.9;
+ font-weight: 500;
+}
+
+// Section
+.section {
+ padding: 80px 0;
+ background: white;
+
+ &:nth-child(even) {
+ background: #f8f9fa;
+ }
+
+ @media (max-width: 768px) {
+ padding: 56px 0;
+ }
+}
+
+.sectionTitle {
+ text-align: center;
+ font-size: 40px;
+ font-weight: 700;
+ margin-bottom: 16px;
+ background: linear-gradient(90deg, #f093fb, #fa709a, #fee140);
+ -webkit-background-clip: text;
+ -webkit-text-fill-color: transparent;
+ background-clip: text;
+
+ @media (max-width: 768px) {
+ font-size: 32px;
+ }
+}
+
+.sectionDesc {
+ text-align: center;
+ font-size: 18px;
+ color: #6c757d;
+ margin-bottom: 48px;
+}
+
+// About Cards
+.aboutCard {
+ padding: 32px 24px;
+ border-radius: 16px;
+ border: 1px solid rgba(15, 23, 42, 0.05);
+ box-shadow: 0 2px 8px rgba(15, 23, 42, 0.08);
+ transition: all 0.3s ease;
+ height: 100%;
+
+ &:hover {
+ box-shadow: 0 8px 24px rgba(15, 23, 42, 0.12);
+ transform: translateY(-8px);
+ }
+
+ .card-title {
+ font-size: 22px;
+ font-weight: 600;
+ margin-bottom: 16px;
+ background: linear-gradient(135deg, #667eea, #764ba2);
+ -webkit-background-clip: text;
+ -webkit-text-fill-color: transparent;
+ background-clip: text;
+ }
+
+ .card-text {
+ font-size: 15px;
+ line-height: 1.6;
+ color: #6c757d;
+ }
+}
+
+.icon {
+ font-size: 48px;
+ margin-bottom: 16px;
+}
+
+// Initiative Section
+.initiative {
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 50%, #f093fb 100%);
+ color: white;
+
+ .sectionTitle {
+ color: white !important;
+ -webkit-text-fill-color: white !important;
+ }
+
+ .sectionDesc {
+ color: rgba(255, 255, 255, 0.9);
+ }
+}
+
+.videoContainer {
+ position: relative;
+ padding-bottom: 56.25%;
+ height: 0;
+ overflow: hidden;
+ background: #000;
+ border-radius: 16px;
+ box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
+
+ iframe {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ border-radius: 16px;
+ }
+}
+
+.initiativeDesc {
+ padding: 24px;
+
+ h3 {
+ font-size: 28px;
+ font-weight: 600;
+ margin-bottom: 24px;
+ color: white;
+ }
+
+ p {
+ font-size: 16px;
+ line-height: 1.8;
+ margin-bottom: 16px;
+ opacity: 0.9;
+ }
+
+ @media (max-width: 768px) {
+ padding: 16px;
+
+ h3 {
+ font-size: 24px;
+ }
+
+ p {
+ font-size: 15px;
+ }
+ }
+}
+
+.ctaButton {
+ margin-top: 24px;
+ padding: 12px 32px;
+ background: linear-gradient(135deg, #fa709a, #fee140);
+ border: none;
+ border-radius: 25px;
+ font-weight: 600;
+ font-size: 16px;
+ box-shadow: 0 4px 15px rgba(250, 112, 154, 0.3);
+ transition: all 0.3s ease;
+
+ &:hover {
+ box-shadow: 0 8px 25px rgba(250, 112, 154, 0.5);
+ transform: translateY(-2px);
+ background: linear-gradient(135deg, #fa709a, #fee140);
+ }
+}
+
+// Rules
+.ruleItem {
+ background: white;
+ padding: 56px 24px 32px;
+ border-radius: 16px;
+ box-shadow: 0 2px 8px rgba(15, 23, 42, 0.08);
+ position: relative;
+ transition: all 0.3s ease;
+ border: 1px solid rgba(15, 23, 42, 0.05);
+ height: 100%;
+
+ &:hover {
+ box-shadow: 0 8px 24px rgba(15, 23, 42, 0.12);
+ transform: translateY(-4px);
+ }
+
+ h4 {
+ font-size: 20px;
+ font-weight: 600;
+ margin-bottom: 12px;
+ color: #0f172a;
+ }
+
+ p {
+ font-size: 15px;
+ line-height: 1.6;
+ color: #6c757d;
+ margin-bottom: 0;
+ }
+}
+
+.ruleNumber {
+ position: absolute;
+ top: -20px;
+ left: 24px;
+ width: 48px;
+ height: 48px;
+ background: linear-gradient(135deg, #667eea, #764ba2);
+ color: white;
+ border-radius: 50%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 24px;
+ font-weight: 700;
+ box-shadow: 0 4px 15px rgba(102, 126, 234, 0.3);
+}
+
+// Winners
+.winnerCard {
+ border-radius: 16px;
+ border: 2px solid #00c9ff;
+ box-shadow: 0 4px 20px rgba(0, 201, 255, 0.3);
+ transition: all 0.3s ease;
+ cursor: pointer;
+ height: 100%;
+
+ &:hover {
+ box-shadow: 0 8px 30px rgba(0, 201, 255, 0.4);
+ transform: translateY(-4px);
+ }
+
+ h3 {
+ font-size: 28px;
+ font-weight: 700;
+ color: #0f172a;
+ margin-bottom: 12px;
+ }
+}
+
+.winnerMeta {
+ display: flex;
+ align-items: center;
+ gap: 12px;
+ color: #6c757d;
+ font-size: 15px;
+ margin-bottom: 12px;
+
+ strong {
+ color: #667eea;
+ font-size: 20px;
+ font-weight: 700;
+ }
+}
+
+.viewHint {
+ color: #667eea;
+ font-size: 14px;
+ font-weight: 600;
+ opacity: 0.7;
+ transition: opacity 0.3s ease;
+}
+
+.winnerCard:hover .viewHint {
+ opacity: 1;
+}
+
+// Filter
+.filterBar {
+ display: flex;
+ justify-content: center;
+ gap: 16px;
+ margin-bottom: 48px;
+}
+
+.filterBtn {
+ padding: 10px 28px;
+ border-radius: 25px;
+ font-size: 15px;
+ font-weight: 500;
+ transition: all 0.3s ease;
+}
+
+// Nominee Cards
+.nomineeCard {
+ border-radius: 16px;
+ box-shadow: 0 2px 8px rgba(15, 23, 42, 0.08);
+ transition: all 0.3s ease;
+ border: 1px solid rgba(15, 23, 42, 0.05);
+ overflow: hidden;
+ height: 100%;
+ display: flex;
+ flex-direction: column;
+
+ &:hover {
+ box-shadow: 0 8px 24px rgba(15, 23, 42, 0.12);
+ transform: translateY(-8px);
+ }
+
+ &.winner {
+ border: 2px solid #00c9ff;
+ box-shadow: 0 4px 20px rgba(0, 201, 255, 0.3);
+ }
+
+ .card-title {
+ font-size: 22px;
+ font-weight: 700;
+ color: #0f172a;
+ }
+
+ .card-body {
+ display: flex;
+ flex-direction: column;
+ flex: 1;
+ }
+}
+
+.videoWrapper {
+ position: relative;
+ padding-bottom: 56.25%;
+ height: 0;
+ overflow: hidden;
+ background: #000;
+
+ iframe {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ }
+}
+
+.reason {
+ background: #f8f9fa;
+ padding: 16px;
+ border-radius: 8px;
+ margin-bottom: 12px;
+ font-size: 14px;
+ line-height: 1.6;
+ color: #0f172a;
+ border-left: 4px solid #667eea;
+
+ strong {
+ display: block;
+ margin-bottom: 8px;
+ }
+
+ p {
+ margin-bottom: 0;
+ }
+}
+
+.votersList {
+ background: #f8f9fa;
+ padding: 12px;
+ border-radius: 8px;
+ margin-bottom: 12px;
+ font-size: 12px;
+
+ strong {
+ color: #0f172a;
+ display: block;
+ margin-bottom: 8px;
+ }
+
+ .badge {
+ margin: 2px;
+ }
+}
+
+.voteSection {
+ border-top: 1px solid rgba(15, 23, 42, 0.1);
+ padding-top: 12px;
+ margin-top: auto;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ gap: 16px;
+}
+
+.voteProgress {
+ flex: 1;
+}
+
+.progressBar {
+ background: #e9ecef;
+ height: 6px;
+ border-radius: 3px;
+ overflow: hidden;
+ margin-bottom: 8px;
+}
+
+.progressFill {
+ background: linear-gradient(90deg, #667eea, #764ba2);
+ height: 100%;
+ transition: width 0.4s ease;
+}
+
+.voteCount {
+ font-size: 13px;
+ color: #6c757d;
+
+ .current {
+ font-weight: 700;
+ color: #667eea;
+ font-size: 18px;
+ }
+}
+
+// FAQ
+.faqCard {
+ border-radius: 16px;
+ border: 1px solid rgba(15, 23, 42, 0.05);
+ box-shadow: 0 2px 8px rgba(15, 23, 42, 0.08);
+ transition: all 0.3s ease;
+
+ &:hover {
+ box-shadow: 0 8px 24px rgba(15, 23, 42, 0.12);
+ transform: translateY(-2px);
+ }
+
+ h5 {
+ background: linear-gradient(135deg, #667eea, #764ba2);
+ -webkit-background-clip: text;
+ -webkit-text-fill-color: transparent;
+ background-clip: text;
+ margin-bottom: 8px;
+ font-size: 16px;
+ font-weight: 600;
+ }
+
+ p {
+ color: #6c757d;
+ line-height: 1.6;
+ font-size: 14px;
+ }
+}
+
+// Responsive
+@media (max-width: 768px) {
+ .stats {
+ flex-direction: row;
+ }
+
+ .statItem {
+ flex: 1;
+ }
+
+ .statNumber {
+ font-size: 40px;
+ }
+
+ .aboutCard,
+ .ruleItem {
+ margin-bottom: 24px;
+ }
+}
diff --git a/pages/article/open-collaborator-award.tsx b/pages/article/open-collaborator-award.tsx
new file mode 100644
index 0000000..0af1d30
--- /dev/null
+++ b/pages/article/open-collaborator-award.tsx
@@ -0,0 +1,588 @@
+import { FC, useContext, useEffect, useState } from 'react';
+import { Badge, Button, Card, Col, Container, Form, Modal, Row } from 'react-bootstrap';
+import { I18nContext } from '../../models/Translation';
+import styles from './open-collaborator-award.module.less';
+
+interface Nomination {
+ id: number;
+ awardName: string;
+ nomineeName: string;
+ nomineeDesc: string;
+ videoUrl: string;
+ bvid: string;
+ reason: string;
+ nominator: string;
+ contact: string;
+ votes: number;
+ voters: string[];
+ createdAt: string;
+}
+
+const initialNominations: Nomination[] = [
+ {
+ id: 1,
+ awardName: '社区老大爷奖',
+ nomineeName: '网名叫唐总',
+ nomineeDesc: '开源市集社区老大爷,资深开源贡献者,社区精神领袖',
+ videoUrl: 'https://www.bilibili.com/video/BV1S44y1J78o/',
+ bvid: 'BV1S44y1J78o',
+ reason: '网名叫唐总就像社区里的老大爷一样,永远那么亲切、可靠。他见证了社区的成长,也包容着每一个新人的青涩。无论何时,只要社区需要,他总是第一个站出来。他不仅分享技术知识,更传递着开源的精神和文化。在他身上,我看到了真正的社区领袖该有的样子——不是权威,而是榜样。',
+ nominator: '诗杰',
+ contact: '',
+ votes: 180,
+ voters: Array.from({ length: 180 }, (_, i) => `voter_${i + 1}`),
+ createdAt: '2025-12-15',
+ },
+ {
+ id: 2,
+ awardName: '星火奖',
+ nomineeName: '水歌',
+ nomineeDesc: '开源布道者,用点滴努力点燃开源星火',
+ videoUrl: 'https://www.bilibili.com/video/BV1Q3411L7zk/',
+ bvid: 'BV1Q3411L7zk',
+ reason: '水歌就像一颗星火,虽然看起来微小,却有着燎原之势。他通过不断的分享和实践,将开源的理念传播给更多人。每一篇文章、每一次演讲、每一行代码,都在点燃着他人心中的开源热情。正是这样的星星之火,让越来越多的人加入到开源协作的行列中来。他让我相信,每个人的努力都有价值。',
+ nominator: 'Miya',
+ contact: '',
+ votes: 150,
+ voters: Array.from({ length: 150 }, (_, i) => `voter_${i + 1}`),
+ createdAt: '2025-12-20',
+ },
+ {
+ id: 3,
+ awardName: '最佳观察者奖',
+ nomineeName: '止戈',
+ nomineeDesc: '敏锐的社区观察者,发现并解决问题的高手',
+ videoUrl: 'https://www.bilibili.com/video/BV1dq4y1t73q/',
+ bvid: 'BV1dq4y1t73q',
+ reason: '止戈有着敏锐的观察力,他总能发现别人忽略的细节和问题。更难能可贵的是,他不仅善于发现问题,还主动寻找解决方案。在社区中,他就像一双明察秋毫的眼睛,帮助我们看到盲区、规避风险、优化流程。他的每一次观察和建议,都让社区变得更好。正是这样的观察者,让我们的协作更加高效。',
+ nominator: '诗杰',
+ contact: '',
+ votes: 120,
+ voters: Array.from({ length: 120 }, (_, i) => `voter_${i + 1}`),
+ createdAt: '2025-12-18',
+ },
+ {
+ id: 4,
+ awardName: '社区之光奖',
+ nomineeName: '诗杰',
+ nomineeDesc: '照亮社区的温暖之光,激励他人前行',
+ videoUrl: 'https://www.bilibili.com/video/BV1JS4y1k7Um/',
+ bvid: 'BV1JS4y1k7Um',
+ reason: '诗杰就像一束光,照亮了社区的每一个角落。他的热情、积极和正能量感染着每一个人。当有人遇到困难时,他总是第一时间伸出援手;当社区需要组织活动时,他总是冲在最前面。他不仅自己发光,更激励着其他人一起发光。在他的影响下,整个社区都变得更加温暖、更有活力。他是真正的社区之光。',
+ nominator: '网名叫唐总',
+ contact: '',
+ votes: 116,
+ voters: Array.from({ length: 116 }, (_, i) => `voter_${i + 1}`),
+ createdAt: '2025-12-22',
+ },
+ {
+ id: 5,
+ awardName: '女王奖',
+ nomineeName: 'Miya',
+ nomineeDesc: '跨界协作推动者,连接不同领域的开放协作人',
+ videoUrl: 'https://www.bilibili.com/video/BV1rq4y1t7Gd/',
+ bvid: 'BV1rq4y1t7Gd',
+ reason: 'Miya在社区中将不同领域、不同背景的开放协作人聚集在一起,激发跨界碰撞的火花。',
+ nominator: '网名叫唐总',
+ contact: '',
+ votes: 100,
+ voters: Array.from({ length: 100 }, (_, i) => `voter_${i + 1}`),
+ createdAt: '2025-12-25',
+ },
+];
+
+const OpenCollaboratorAward: FC = () => {
+ const { t } = useContext(I18nContext);
+ const [nominations, setNominations] = useState([]);
+ const [filter, setFilter] = useState<'all' | 'pending' | 'success'>('all');
+ const [showModal, setShowModal] = useState(false);
+ const [userId, setUserId] = useState('');
+
+ // 初始化数据
+ useEffect(() => {
+ // 获取或创建用户ID
+ let uid = localStorage.getItem('userId');
+ if (!uid) {
+ uid = `user_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
+ localStorage.setItem('userId', uid);
+ }
+ setUserId(uid);
+
+ // 强制使用最新的初始数据(忽略 localStorage 中的旧数据)
+ setNominations(initialNominations);
+ localStorage.setItem('nominations', JSON.stringify(initialNominations));
+ }, []);
+
+ const saveData = (data: Nomination[]) => {
+ setNominations(data);
+ localStorage.setItem('nominations', JSON.stringify(data));
+ };
+
+ const extractBVID = (url: string): string | null => {
+ const match = url.match(/BV[a-zA-Z0-9]+/);
+ return match ? match[0] : null;
+ };
+
+ const getBilibiliEmbed = (bvid: string): string => {
+ return `https://player.bilibili.com/player.html?bvid=${bvid}&page=1&high_quality=1&danmaku=0&autoplay=0`;
+ };
+
+ const handleVote = (nominationId: number) => {
+ const nomination = nominations.find((n) => n.id === nominationId);
+ if (!nomination) return;
+
+ if (nomination.voters.includes(userId)) {
+ alert('你已经为这个提名投过票了!');
+ return;
+ }
+
+ const willWin = nomination.votes + 1 >= 10;
+ const message = willWin
+ ? `确认投票吗?\n\n"${nomination.awardName}" 提名人 ${nomination.nomineeName} 即将获奖!\n投票后你需要和其他投票人共同分摊奖杯制作费用(预计每人 50-80 元)。`
+ : `确认为 ${nomination.nomineeName} 投票吗?\n\n当前 ${nomination.votes} 票,还需要 ${10 - nomination.votes} 票奖项即可成立。\n投票后如果奖项成立,你需要和其他投票人共同分摊奖杯制作费用。`;
+
+ if (!confirm(message)) return;
+
+ const updatedNominations = nominations.map((n) =>
+ n.id === nominationId
+ ? { ...n, votes: n.votes + 1, voters: [...n.voters, userId] }
+ : n
+ );
+ saveData(updatedNominations);
+
+ if (willWin) {
+ alert(`恭喜!${nomination.nomineeName} 的提名已达到 10 票,奖项正式成立!\n\n我们会尽快联系所有投票人确认费用分摊事宜。`);
+ } else {
+ alert(`✅ 投票成功!当前 ${nomination.votes + 1} 票`);
+ }
+ };
+
+ const handleSubmit = (e: React.FormEvent) => {
+ e.preventDefault();
+ const form = e.currentTarget;
+ const formData = new FormData(form);
+
+ const videoUrl = formData.get('videoUrl') as string;
+ const bvid = extractBVID(videoUrl);
+
+ if (!bvid) {
+ alert('请输入有效的B站视频链接!');
+ return;
+ }
+
+ const newNomination: Nomination = {
+ id: nominations.length > 0 ? Math.max(...nominations.map((n) => n.id)) + 1 : 1,
+ awardName: '开放协作人奖',
+ nomineeName: formData.get('nomineeName') as string,
+ nomineeDesc: (formData.get('nomineeDesc') as string) || '',
+ videoUrl,
+ bvid,
+ reason: formData.get('reason') as string,
+ nominator: formData.get('nominator') as string,
+ contact: (formData.get('contact') as string) || '',
+ votes: 0,
+ voters: [],
+ createdAt: new Date().toISOString().split('T')[0],
+ };
+
+ saveData([newNomination, ...nominations]);
+ form.reset();
+ setShowModal(false);
+ alert('✅ 提名提交成功!感谢你的参与!');
+
+ setTimeout(() => {
+ document.getElementById('nominees')?.scrollIntoView({ behavior: 'smooth' });
+ }, 100);
+ };
+
+ const filteredNominations = nominations.filter((n) => {
+ if (filter === 'pending') return n.votes < 10;
+ if (filter === 'success') return n.votes >= 10;
+ return true;
+ });
+
+ const winners = nominations.filter((n) => n.votes >= 10);
+ const totalVotes = 666; // 固定显示
+
+ return (
+
+ {/* Hero 区域 */}
+
+
+ 致敬每一位开放协作者
+ 感谢那些在过去一年里给你留下深刻印象、对你有帮助的人
+
+
+ {nominations.length}
+ 总提名数
+
+
+ {winners.length}
+ 获奖人数
+
+
+ {totalVotes}
+ 总投票数
+
+
+
+
+
+ {/* 关于奖项 */}
+
+
+ 关于奖项
+
+
+
+
+ 🌟
+ 奖项意义
+
+ 由「开源市集」社区发起,旨在表彰那些在开源协作中展现出卓越精神和无私奉献的个人。
+
+
+
+
+
+
+
+ 🎯
+ 评选标准
+
+ 任何在过去一年里给你留下深刻印象或对你有帮助的人,都值得被提名和表彰。
+
+
+
+
+
+
+
+ 🏆
+ 共创价值
+
+ 当提名获得至少10票支持,所有投票人将共同分摊费用,为获奖者制作专属奖杯。
+
+
+
+
+
+
+
+
+ {/* 倡议视频 */}
+
+
+ 开放协作人奖提名倡议
+
+
+
+
+
+
+
+
+
为什么发起这个奖项?
+
+ 在开源社区中,有太多默默付出的人,他们的贡献往往被忽视。开放协作人奖希望通过社区的力量,让每一个帮助过你的人都能被看见、被感谢、被铭记。
+
+
+ 这不仅仅是一个奖项,更是一种文化的传递——让感恩成为习惯,让协作成为力量。
+
+
+
+
+
+
+
+
+ {/* 规则说明 */}
+
+
+ 参与规则
+
+ {[
+ { num: 1, title: '提名', desc: '任何人都可以提名在过去一年里对自己有帮助的人,通过视频介绍提名理由' },
+ { num: 2, title: '投票', desc: '社区成员可以为认同的提名投票,每人每个提名只能投一票' },
+ { num: 3, title: '成立', desc: '当提名获得至少10票时,奖项正式成立,被提名人成为获奖者' },
+ { num: 4, title: '奖杯', desc: '所有投票人平摊费用,共同为获奖者制作专属奖杯' },
+ ].map((rule) => (
+
+
+
{rule.num}
+
{rule.title}
+
{rule.desc}
+
+
+ ))}
+
+
+
+
+ {/* 获奖者榜单 */}
+ {winners.length > 0 && (
+
+
+ 获奖者榜单
+
+ {winners.map((winner) => (
+
+ {
+ document
+ .getElementById(`nominee-${winner.id}`)
+ ?.scrollIntoView({ behavior: 'smooth', block: 'center' });
+ }}
+ >
+
+
+ {winner.awardName}
+
+ {winner.nomineeName}
+
+ 提名人:{winner.nominator}
+ |
+
+ 投票数:{winner.votes}
+
+
+ 点击查看提名视频 →
+
+
+
+ ))}
+
+
+
+ )}
+
+ {/* 提名展示 */}
+
+
+ 提名展示
+
+ {(['all', 'pending', 'success'] as const).map((f) => (
+
+ ))}
+
+
+ {filteredNominations.length === 0 ? (
+
+ 暂无提名
+
+ ) : (
+ filteredNominations.map((nomination) => {
+ const progress = Math.min((nomination.votes / 10) * 100, 100);
+ const hasVoted = nomination.voters.includes(userId);
+ const isWinner = nomination.votes >= 10;
+ const displayVoters = nomination.voters.slice(0, 5);
+ const remainingCount = Math.max(0, nomination.voters.length - 5);
+
+ return (
+
+
+
+
+
+
+
+ {nomination.awardName}
+
+
+ {nomination.nomineeName}
+ {isWinner && (
+
+ 已获奖
+
+ )}
+
+ {nomination.nomineeDesc && (
+ {nomination.nomineeDesc}
+ )}
+
+
提名理由:
+
{nomination.reason}
+
+
+ 提名人:{nomination.nominator} · {nomination.createdAt}
+
+ {nomination.voters.length > 0 && (
+
+ 投票人:
+ {displayVoters.map((voter, idx) => (
+
+ {voter}
+
+ ))}
+ {remainingCount > 0 && (
+ +{remainingCount}
+ )}
+
+ )}
+
+
+
+
+ {nomination.votes} / 10 票
+ {isWinner && ✓ 奖项已成立}
+
+
+
+
+
+
+
+ );
+ })
+ )}
+
+
+
+
+
+
+
+ {/* FAQ */}
+
+
+ 常见问题
+
+
+ {[
+ {
+ q: 'Q: 谁可以参与提名?',
+ a: 'A: 任何人都可以提名在过去一年里对自己有帮助或留下深刻印象的人。',
+ },
+ {
+ q: 'Q: 如何制作提名视频?',
+ a: 'A: 可以用手机或电脑录制,真诚地讲述为什么要提名TA、TA做了什么让你印象深刻的事情。上传到B站后将链接粘贴到提名表单即可。',
+ },
+ {
+ q: 'Q: 投票后需要支付多少费用?',
+ a: 'A: 只有当提名达到10票成立后,投票人才需要分摊奖杯制作费用。具体金额会在投票时说明,通常每人十几元人民币。',
+ },
+ {
+ q: 'Q: 可以投多个提名吗?',
+ a: 'A: 可以。你可以为多个不同的提名投票,但每个提名只能投一票。',
+ },
+ {
+ q: 'Q: 奖杯会寄给获奖者吗?',
+ a: 'A: 是的。达到10票后,我们会联系获奖者确认收件地址,制作完成后寄出。',
+ },
+ ].map((faq, idx) => (
+
+
+ {faq.q}
+ {faq.a}
+
+
+ ))}
+
+
+
+
+
+ {/* 提交提名表单 Modal */}
+
setShowModal(false)} size="lg" centered>
+
+ 提交提名
+
+
+
+ 被提名人姓名/网名 *
+
+
+
+ 被提名人简介
+
+
+
+ 提名视频链接 *
+
+ 请上传视频到B站,然后粘贴链接
+
+
+ 提名理由(文字版) *
+
+
+
+ 你的姓名/网名 *
+
+
+
+ 联系方式
+
+
+
+
+
+
+
+ );
+};
+
+export default OpenCollaboratorAward;