實現完整的後台得獎資訊
This commit is contained in:
@@ -102,6 +102,11 @@ export function CompetitionManagement() {
|
||||
// 可用用戶狀態
|
||||
const [availableUsers, setAvailableUsers] = useState<any[]>([])
|
||||
const [isLoadingUsers, setIsLoadingUsers] = useState(false)
|
||||
|
||||
// 獎項資料庫整合狀態
|
||||
const [dbAwards, setDbAwards] = useState<any[]>([])
|
||||
const [isLoadingAwards, setIsLoadingAwards] = useState(false)
|
||||
const [awardStats, setAwardStats] = useState<any>(null)
|
||||
|
||||
const [showCreateCompetition, setShowCreateCompetition] = useState(false)
|
||||
const [showAddJudge, setShowAddJudge] = useState(false)
|
||||
@@ -704,6 +709,7 @@ export function CompetitionManagement() {
|
||||
fetchTeams()
|
||||
fetchTeamStats()
|
||||
fetchAvailableApps()
|
||||
loadAwardsData()
|
||||
}, [])
|
||||
|
||||
// 當競賽列表載入完成後,載入每個競賽的評分進度
|
||||
@@ -1980,6 +1986,15 @@ export function CompetitionManagement() {
|
||||
}
|
||||
|
||||
const handleViewAward = async (award: any) => {
|
||||
console.log('🎯 handleViewAward 被調用:', {
|
||||
award: award ? {
|
||||
id: award.id,
|
||||
competitionId: award.competitionId,
|
||||
awardName: award.award_name,
|
||||
hasCompetitionId: !!award.competitionId
|
||||
} : null
|
||||
});
|
||||
|
||||
setSelectedAward(award)
|
||||
setShowAwardDetail(true)
|
||||
|
||||
@@ -1992,6 +2007,7 @@ export function CompetitionManagement() {
|
||||
|
||||
if (data.success) {
|
||||
console.log('✅ 獲取到評審團:', data.data.length, '位');
|
||||
console.log('👥 評審團詳細資料:', data.data);
|
||||
setCompetitionJudges(data.data);
|
||||
} else {
|
||||
console.error('❌ 獲取評審團失敗:', data.message);
|
||||
@@ -2001,6 +2017,8 @@ export function CompetitionManagement() {
|
||||
console.error('❌ 載入評審團失敗:', error);
|
||||
setCompetitionJudges([]);
|
||||
}
|
||||
} else {
|
||||
console.log('❌ 獎項沒有 competitionId,無法載入評審團');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2080,6 +2098,41 @@ export function CompetitionManagement() {
|
||||
setShowManualScoring(true)
|
||||
}
|
||||
|
||||
// 載入獎項資料
|
||||
const loadAwardsData = async () => {
|
||||
setIsLoadingAwards(true)
|
||||
try {
|
||||
console.log('🔍 開始載入獎項資料...')
|
||||
const response = await fetch('/api/admin/awards')
|
||||
const data = await response.json()
|
||||
|
||||
if (data.success) {
|
||||
console.log('✅ 獎項資料載入成功:', data.data.length, '個獎項')
|
||||
setDbAwards(data.data)
|
||||
|
||||
// 計算獎項統計
|
||||
const stats = {
|
||||
total: data.data.length,
|
||||
top3: data.data.filter((award: any) => award.rank && award.rank <= 3).length,
|
||||
popular: data.data.filter((award: any) => award.award_type === 'popular').length,
|
||||
competitions: [...new Set(data.data.map((award: any) => award.competition_id))].length
|
||||
}
|
||||
setAwardStats(stats)
|
||||
console.log('📊 獎項統計:', stats)
|
||||
} else {
|
||||
console.error('❌ 獎項資料載入失敗:', data.message)
|
||||
setDbAwards([])
|
||||
setAwardStats({ total: 0, top3: 0, popular: 0, competitions: 0 })
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('❌ 載入獎項資料失敗:', error)
|
||||
setDbAwards([])
|
||||
setAwardStats({ total: 0, top3: 0, popular: 0, competitions: 0 })
|
||||
} finally {
|
||||
setIsLoadingAwards(false)
|
||||
}
|
||||
}
|
||||
|
||||
// 載入競賽相關數據用於評分
|
||||
const loadCompetitionDataForScoring = async (competition: any) => {
|
||||
try {
|
||||
@@ -2735,7 +2788,8 @@ export function CompetitionManagement() {
|
||||
|
||||
// 获取筛选后的奖项
|
||||
const getFilteredAwards = () => {
|
||||
let filteredAwards = [...awards]
|
||||
// 使用資料庫中的獎項資料,如果沒有則使用 context 中的資料作為備用
|
||||
let filteredAwards = dbAwards.length > 0 ? [...dbAwards] : [...awards]
|
||||
|
||||
// 搜索功能 - 按应用名称、创作者或奖项名称搜索
|
||||
if (awardSearchQuery.trim()) {
|
||||
@@ -3888,24 +3942,26 @@ export function CompetitionManagement() {
|
||||
{/* 统计信息 */}
|
||||
<div className="grid grid-cols-2 md:grid-cols-4 gap-4 mt-4">
|
||||
<div className="text-center p-3 bg-blue-50 rounded-lg">
|
||||
<div className="text-lg font-bold text-blue-600">{getFilteredAwards().length}</div>
|
||||
<div className="text-lg font-bold text-blue-600">
|
||||
{isLoadingAwards ? '...' : getFilteredAwards().length}
|
||||
</div>
|
||||
<div className="text-xs text-blue-600">篩選結果</div>
|
||||
</div>
|
||||
<div className="text-center p-3 bg-yellow-50 rounded-lg">
|
||||
<div className="text-lg font-bold text-yellow-600">
|
||||
{getFilteredAwards().filter((a) => parseInt(a.rank) > 0 && parseInt(a.rank) <= 3).length}
|
||||
{isLoadingAwards ? '...' : (awardStats?.top3 ?? getFilteredAwards().filter((a) => parseInt(a.rank) > 0 && parseInt(a.rank) <= 3).length)}
|
||||
</div>
|
||||
<div className="text-xs text-yellow-600">前三名獎項</div>
|
||||
</div>
|
||||
<div className="text-center p-3 bg-red-50 rounded-lg">
|
||||
<div className="text-lg font-bold text-red-600">
|
||||
{getFilteredAwards().filter((a) => a.awardType === "popular").length}
|
||||
{isLoadingAwards ? '...' : (awardStats?.popular ?? getFilteredAwards().filter((a) => a.award_type === "popular").length)}
|
||||
</div>
|
||||
<div className="text-xs text-red-600">人氣獎項</div>
|
||||
</div>
|
||||
<div className="text-center p-3 bg-green-50 rounded-lg">
|
||||
<div className="text-lg font-bold text-green-600">
|
||||
{new Set(getFilteredAwards().map((a) => `${a.year}-${a.month}`)).size}
|
||||
{isLoadingAwards ? '...' : (awardStats?.competitions ?? new Set(getFilteredAwards().map((a) => `${a.year}-${a.month}`)).size)}
|
||||
</div>
|
||||
<div className="text-xs text-green-600">競賽場次</div>
|
||||
</div>
|
||||
@@ -7815,52 +7871,68 @@ export function CompetitionManagement() {
|
||||
<Label htmlFor="award-name">
|
||||
獎項名稱 <span className="text-red-500">*</span>
|
||||
</Label>
|
||||
<Input
|
||||
id="award-name"
|
||||
value={newAward.awardName}
|
||||
onChange={(e) => setNewAward({ ...newAward, awardName: e.target.value })}
|
||||
placeholder="例如:最佳創新獎、金獎、銀獎"
|
||||
/>
|
||||
<Select
|
||||
value={newAward.customAwardTypeId || "custom-input"}
|
||||
onValueChange={(value: any) => {
|
||||
if (value === "custom-input") {
|
||||
setNewAward({ ...newAward, customAwardTypeId: "", awardName: "" })
|
||||
} else {
|
||||
// 檢查是否為自定義獎項類型
|
||||
const customAwardType = competitionAwardTypes.find(type => type.id === value)
|
||||
if (customAwardType) {
|
||||
setNewAward({
|
||||
...newAward,
|
||||
customAwardTypeId: value,
|
||||
awardName: customAwardType.name
|
||||
})
|
||||
}
|
||||
}
|
||||
}}
|
||||
disabled={loadingAwardTypes}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder={loadingAwardTypes ? "載入中..." : "選擇獎項名稱或自定義輸入"} />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="custom-input">自定義輸入</SelectItem>
|
||||
{competitionAwardTypes.map((awardType) => (
|
||||
<SelectItem key={awardType.id} value={awardType.id}>
|
||||
<div className="flex items-center space-x-2">
|
||||
<span>{awardType.icon}</span>
|
||||
<span>{awardType.name}</span>
|
||||
</div>
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
{!newAward.customAwardTypeId && (
|
||||
<Input
|
||||
id="award-name"
|
||||
value={newAward.awardName}
|
||||
onChange={(e) => setNewAward({ ...newAward, awardName: e.target.value })}
|
||||
placeholder="例如:最佳創新獎、金獎、銀獎、人氣獎"
|
||||
/>
|
||||
)}
|
||||
{competitionAwardTypes.length > 0 && (
|
||||
<p className="text-xs text-gray-500">
|
||||
此競賽有 {competitionAwardTypes.length} 個自定義獎項名稱可選擇
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* 獎項類型 */}
|
||||
<div className="space-y-2">
|
||||
<Label>獎項類型</Label>
|
||||
<Select
|
||||
value={newAward.customAwardTypeId ?? newAward.awardType}
|
||||
value={newAward.awardType}
|
||||
onValueChange={(value: any) => {
|
||||
// 檢查是否為自定義獎項類型
|
||||
const customAwardType = competitionAwardTypes.find(type => type.id === value)
|
||||
if (customAwardType) {
|
||||
setNewAward({
|
||||
...newAward,
|
||||
awardType: 'custom',
|
||||
customAwardTypeId: value,
|
||||
awardName: customAwardType.name
|
||||
})
|
||||
} else {
|
||||
setNewAward({ ...newAward, awardType: value, customAwardTypeId: "" })
|
||||
}
|
||||
setNewAward({ ...newAward, awardType: value })
|
||||
}}
|
||||
disabled={loadingAwardTypes}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder={loadingAwardTypes ? "載入中..." : "選擇獎項類型"} />
|
||||
<SelectValue placeholder="選擇獎項類型" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{competitionAwardTypes.length > 0 ? (
|
||||
// 顯示競賽自定義的獎項類型
|
||||
competitionAwardTypes.map((awardType) => (
|
||||
<SelectItem key={awardType.id} value={awardType.id}>
|
||||
<div className="flex items-center space-x-2">
|
||||
<span>{awardType.icon}</span>
|
||||
<span>{awardType.name}</span>
|
||||
</div>
|
||||
</SelectItem>
|
||||
))
|
||||
) : (
|
||||
// 如果沒有自定義獎項類型,顯示預設選項
|
||||
<>
|
||||
<SelectItem value="gold">🥇 金獎</SelectItem>
|
||||
<SelectItem value="silver">🥈 銀獎</SelectItem>
|
||||
<SelectItem value="bronze">🥉 銅獎</SelectItem>
|
||||
@@ -7868,15 +7940,8 @@ export function CompetitionManagement() {
|
||||
<SelectItem value="innovation">💡 創新獎</SelectItem>
|
||||
<SelectItem value="technical">⚙️ 技術獎</SelectItem>
|
||||
<SelectItem value="custom">🏆 自定義獎項</SelectItem>
|
||||
</>
|
||||
)}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
{competitionAwardTypes.length > 0 && (
|
||||
<p className="text-xs text-gray-500">
|
||||
此競賽有 {competitionAwardTypes.length} 個自定義獎項類型
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* 獎項類別 */}
|
||||
|
Reference in New Issue
Block a user