diff --git a/pages/article/open-collaborator-award.mdx b/pages/article/open-collaborator-award.mdx
index 370a684..eaaa8e6 100644
--- a/pages/article/open-collaborator-award.mdx
+++ b/pages/article/open-collaborator-award.mdx
@@ -1,6 +1,40 @@
# 开放协作人奖
-
+## 专用页面已上线
+
+我们为开放协作人奖创建了全新的专用页面,提供更丰富的功能和更好的用户体验。
+
+### 新功能特色
+
+- 📝 **在线推荐功能** - 直接在页面提交候选人推荐
+- 💾 **实时数据同步** - 与飞书多维表格无缝集成
+- 🎨 **现代化界面** - 响应式设计,支持各种设备
+- 📊 **统计信息** - 实时显示推荐数量和投票统计
+- 🔍 **候选人展示** - 完整的候选人信息和推荐理由
+
+### 立即访问
+
+
+
+### 奖项介绍影片
+
+
+
+### 快速导航
+
+- [🏆 开放协作人奖专页](/award/open-collaborator-award) - 查看所有候选人和在线推荐
+- [🎖️ 所有奖项](/award) - 浏览开源市集所有奖项类别
+- [👥 推荐候选人](/award/open-collaborator-award#nominate) - 直接跳转到推荐表单
+
+---
+
+*如果您在使用过程中遇到任何问题,请通过官方渠道联系我们。*
\ No newline at end of file
diff --git a/pages/award/index.tsx b/pages/award/index.tsx
index a0e22bd..f9953ef 100644
--- a/pages/award/index.tsx
+++ b/pages/award/index.tsx
@@ -1,16 +1,309 @@
import { cache, compose, errorLogger } from 'next-ssr-middleware';
import { FC } from 'react';
+import { observer } from 'mobx-react-lite';
+import { Card, Col, Row, Badge, Button } from 'react-bootstrap';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { faTrophy, faUsers, faHeart, faEye, faArrowRight } from '@fortawesome/free-solid-svg-icons';
+import Link from 'next/link';
import { Award, AwardModel } from '../../models/Award';
+import { MainLayout } from '../../components/Layout';
export const getServerSideProps = compose(cache(), errorLogger, async () => {
- const awards = await new AwardModel().getAll();
+ const awardModel = new AwardModel();
+ const awards = await awardModel.getAll();
- return { props: { awards } };
+ // Group awards by type
+ const awardStats = awards.reduce((acc, award) => {
+ const awardName = award.awardName?.toString() || 'Unknown';
+ if (!acc[awardName]) {
+ acc[awardName] = {
+ name: awardName,
+ nominations: [],
+ totalVotes: 0
+ };
+ }
+ acc[awardName].nominations.push(award);
+ acc[awardName].totalVotes += Number(award.votes || 0);
+ return acc;
+ }, {} as Record
);
+
+ const awardTypes = Object.values(awardStats);
+
+ return {
+ props: {
+ awards,
+ awardTypes,
+ totalNominations: awards.length
+ }
+ };
});
-const AwardPage: FC<{ awards: Award[] }> = ({ awards }) => {
- return <>>;
+interface Props {
+ awards: Award[];
+ awardTypes: { name: string; nominations: Award[]; totalVotes: number }[];
+ totalNominations: number;
+}
+
+const AwardTypeCard: FC<{
+ awardType: { name: string; nominations: Award[]; totalVotes: number };
+ isOpenCollaborator?: boolean;
+}> = ({ awardType, isOpenCollaborator = false }) => {
+ const getAwardIcon = (name: string) => {
+ if (name.includes('协作') || name.includes('Collaborator')) return faUsers;
+ return faTrophy;
+ };
+
+ const getAwardColor = (name: string) => {
+ if (name.includes('协作') || name.includes('Collaborator')) return 'primary';
+ return 'warning';
+ };
+
+ const getAwardDescription = (name: string) => {
+ if (name.includes('协作') || name.includes('Collaborator')) {
+ return '表彰在開源領域展現卓越協作精神與傑出貢獻的個人與團隊';
+ }
+ return '表彰在各領域展現傑出成就的個人與項目';
+ };
+
+ return (
+
+
+
+
+
+
+
+
{awardType.name}
+ {isOpenCollaborator && (
+ Featured Award
+ )}
+
+
+
+
+ {getAwardDescription(awardType.name)}
+
+
+
+
+
+
{awardType.nominations.length}
+
推薦數
+
+
+
{awardType.totalVotes}
+
總票數
+
+
+
+
+ 最新推薦: {awardType.nominations.length > 0
+ ? new Date(Math.max(...awardType.nominations.map(n =>
+ new Date(n.createdAt?.toString() || 0).getTime()
+ ))).toLocaleDateString()
+ : '無'
+ }
+
+
+
+
+ {/* Recent nominations preview */}
+ {awardType.nominations.length > 0 && (
+
+
最新推薦:
+
+ {awardType.nominations.slice(0, 2).map((nomination, index) => (
+
+
+
+ {nomination.nomineeName || '未具名候選人'}
+
+ {nomination.votes && Number(nomination.votes) > 0 && (
+
+
+ {nomination.votes}
+
+ )}
+
+ ))}
+ {awardType.nominations.length > 2 && (
+
+ 還有 {awardType.nominations.length - 2} 位候選人...
+
+ )}
+
+
+ )}
+
+
+ {isOpenCollaborator ? (
+
+
+
+ ) : (
+
+ )}
+
+
+
+ );
};
-export default AwardPage;
+const AwardPage: FC = observer(({ awards, awardTypes, totalNominations }) => {
+ const openCollaboratorAward = awardTypes.find(
+ type => type.name.includes('协作') || type.name.includes('Collaborator')
+ );
+
+ const otherAwards = awardTypes.filter(
+ type => !type.name.includes('协作') && !type.name.includes('Collaborator')
+ );
+
+ return (
+
+
+ {/* Hero Section */}
+
+
+
+
開源市集獎項
+
+ 表彰開源社群中的傑出貢獻者與創新項目
+
+
+
+ {awardTypes.length}
+
+ 獎項類別
+
+
+
+ {totalNominations}
+
+ 總推薦數
+
+
+
+ {awardTypes.reduce((sum, type) => sum + type.totalVotes, 0)}
+
+ 總票數
+
+
+
+
+
+ {/* Featured Award - Open Collaborator Award */}
+ {openCollaboratorAward && (
+
+
+
+
+ 精選獎項
+
+ Featured
+
+
+
+
+
+
+
+
+
+
立即參與
+
+ 推薦您認為值得表彰的開源協作者,讓更多人看見他們的貢獻!
+
+
+
+
+
+
+
+
+
+ )}
+
+ {/* All Award Types */}
+
+
+
+ 所有獎項類別
+
+
+ {awardTypes.length > 0 ? (
+
+ {awardTypes.map((awardType, index) => (
+
+
+
+ ))}
+
+ ) : (
+
+
+
+ 尚無獎項
+
+ 目前還沒有任何獎項推薦,成為第一個推薦者吧!
+
+
+
+
+
+
+ )}
+
+
+ {/* Statistics Section */}
+
+
+
+ {awardTypes.length}
+ 獎項類別
+
+
+ {totalNominations}
+ 總推薦數
+
+
+
+ {awardTypes.reduce((sum, type) => sum + type.totalVotes, 0)}
+
+ 總票數
+
+
+
+ {new Date().getFullYear()}
+
+ 年度獎項
+
+
+
+
+
+ );
+});
+
+export default AwardPage;
\ No newline at end of file
diff --git a/pages/award/open-collaborator-award.tsx b/pages/award/open-collaborator-award.tsx
new file mode 100644
index 0000000..ded0dda
--- /dev/null
+++ b/pages/award/open-collaborator-award.tsx
@@ -0,0 +1,328 @@
+import { cache, compose, errorLogger } from 'next-ssr-middleware';
+import { FC, useState } from 'react';
+import { observer } from 'mobx-react-lite';
+import { Card, Col, Row, Form, Button, Alert, Modal, Badge } from 'react-bootstrap';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { faTrophy, faUsers, faHeart, faPlus } from '@fortawesome/free-solid-svg-icons';
+
+import { Award, AwardModel } from '../../models/Award';
+import { MainLayout } from '../../components/Layout';
+
+export const getServerSideProps = compose(cache(), errorLogger, async () => {
+ const awardModel = new AwardModel();
+ const awards = await awardModel.getAll();
+
+ // Filter for Open Collaborator Award nominations
+ const openCollaboratorNominations = awards.filter(
+ award => award.awardName === '开放协作人奖' || award.awardName === 'Open Collaborator Award'
+ );
+
+ return {
+ props: {
+ nominations: openCollaboratorNominations || [],
+ totalNominations: openCollaboratorNominations.length
+ }
+ };
+});
+
+interface Props {
+ nominations: Award[];
+ totalNominations: number;
+}
+
+const NominationCard: FC<{ nomination: Award }> = ({ nomination }) => (
+
+
+
+
+
+ {nomination.nomineeName || '未具名被推薦者'}
+
+
+
+ {nomination.votes || 0}
+
+
+
+
+ {nomination.nomineeDesc || '暫無描述'}
+
+
+
+
推薦理由
+
+ {nomination.reason || '暫無推薦理由'}
+
+
+
+
+
+ 推薦人: {nomination.nominator || '匿名'}
+ {nomination.createdAt && (
+ <> · {new Date(nomination.createdAt.toString()).toLocaleDateString()}>
+ )}
+
+
+
+
+);
+
+const NominationForm: FC<{ onSubmit: (data: any) => void; onCancel: () => void }> = ({
+ onSubmit,
+ onCancel
+}) => {
+ const [formData, setFormData] = useState({
+ nomineeName: '',
+ nomineeDesc: '',
+ reason: '',
+ nominator: '',
+ videoUrl: ''
+ });
+
+ const handleChange = (field: string, value: string) => {
+ setFormData(prev => ({ ...prev, [field]: value }));
+ };
+
+ const handleSubmit = (e: React.FormEvent) => {
+ e.preventDefault();
+ onSubmit(formData);
+ };
+
+ return (
+
+ 被推薦者描述
+ handleChange('nomineeDesc', e.target.value)}
+ placeholder="請簡要描述被推薦者的背景和貢獻"
+ />
+
+
+
+ 推薦理由 *
+ handleChange('reason', e.target.value)}
+ placeholder="請詳細說明推薦理由,包括具體的開源貢獻和協作事例"
+ required
+ />
+
+
+
+ 相關影片連結
+ handleChange('videoUrl', e.target.value)}
+ placeholder="https://... (可選)"
+ />
+
+
+
+
+
+
+
+ );
+};
+
+const OpenCollaboratorAwardPage: FC = observer(({ nominations, totalNominations }) => {
+ const [showNominationForm, setShowNominationForm] = useState(false);
+ const [submitSuccess, setSubmitSuccess] = useState(false);
+ const [submitError, setSubmitError] = useState(null);
+
+ const handleNominationSubmit = async (formData: any) => {
+ try {
+ const awardModel = new AwardModel();
+
+ await awardModel.create({
+ awardName: '开放协作人奖',
+ nomineeName: formData.nomineeName,
+ nomineeDesc: formData.nomineeDesc,
+ reason: formData.reason,
+ nominator: formData.nominator || '匿名',
+ videoUrl: formData.videoUrl,
+ votes: 0,
+ createdAt: new Date().toISOString()
+ });
+
+ setSubmitSuccess(true);
+ setShowNominationForm(false);
+
+ // Refresh page after successful submission
+ setTimeout(() => {
+ window.location.reload();
+ }, 2000);
+
+ } catch (error) {
+ setSubmitError('提交失敗,請稍後再試');
+ console.error('Nomination submission error:', error);
+ }
+ };
+
+ return (
+
+
+ {/* Hero Section */}
+
+
+
+
開放協作人獎
+
+ 表彰在開源領域展現卓越協作精神與傑出貢獻的個人與團隊
+
+
+
+ {totalNominations}
+
+ 總推薦數
+
+
+
+ {new Date().getFullYear()}
+
+ 年度獎項
+
+
+
+
+
+ {/* Success Alert */}
+ {submitSuccess && (
+
setSubmitSuccess(false)}>
+
+ 推薦提交成功!感謝您的參與,頁面將自動刷新。
+
+ )}
+
+ {/* Error Alert */}
+ {submitError && (
+
setSubmitError(null)}>
+ {submitError}
+
+ )}
+
+ {/* Award Introduction Video */}
+
+
+
+
+
+ 獎項介紹影片
+
+
+
+
+
+
+
+
+
+
+ {/* Action Section */}
+
+
+
+ 推薦名單
+
+
+
+
+ {/* Nominations Grid */}
+ {nominations.length > 0 ? (
+
+ {nominations.map((nomination, index) => (
+
+
+
+ ))}
+
+ ) : (
+
+
+
+ 尚無推薦
+ 成為第一個推薦開放協作人獎候選人的人!
+
+
+
+ )}
+
+ {/* Nomination Form Modal */}
+
setShowNominationForm(false)}
+ size="lg"
+ centered
+ >
+
+
+
+ 推薦開放協作人獎候選人
+
+
+
+ setShowNominationForm(false)}
+ />
+
+
+
+
+ );
+});
+
+export default OpenCollaboratorAwardPage;
\ No newline at end of file