新增得獎更新、刪除的功能
This commit is contained in:
@@ -71,6 +71,8 @@ export function CompetitionManagement() {
|
||||
deleteJudge,
|
||||
awards,
|
||||
addAward,
|
||||
updateAward,
|
||||
deleteAward,
|
||||
getAppDetailedScores,
|
||||
judgeScores,
|
||||
getAppJudgeScores,
|
||||
@@ -1081,9 +1083,11 @@ export function CompetitionManagement() {
|
||||
}
|
||||
|
||||
if (judgesData.success) {
|
||||
console.log('✅ 載入評審成功:', judgesData.data?.length || 0, '位評審')
|
||||
console.log('👥 評審詳細資料:', judgesData.data)
|
||||
setCompetitionJudges(judgesData.data)
|
||||
} else {
|
||||
console.error('載入評審失敗:', judgesData.message)
|
||||
console.error('❌ 載入評審失敗:', judgesData.message)
|
||||
setCompetitionJudges([])
|
||||
}
|
||||
} catch (error) {
|
||||
@@ -1870,7 +1874,7 @@ export function CompetitionManagement() {
|
||||
|
||||
// 根據獎項類型設定圖標
|
||||
let icon = "🏆"
|
||||
switch (newAward.awardType) {
|
||||
switch (newAward.awardType as any) {
|
||||
case "gold": icon = "🥇"; break;
|
||||
case "silver": icon = "🥈"; break;
|
||||
case "bronze": icon = "🥉"; break;
|
||||
@@ -1908,9 +1912,14 @@ export function CompetitionManagement() {
|
||||
|
||||
console.log('📝 準備獎項數據:', awardData)
|
||||
|
||||
// 調用 API 創建獎項
|
||||
const response = await fetch('/api/admin/awards', {
|
||||
method: 'POST',
|
||||
// 判斷是創建還是編輯模式
|
||||
const isEditMode = selectedAward && selectedAward.id
|
||||
const apiUrl = isEditMode ? `/api/admin/awards/${selectedAward.id}` : '/api/admin/awards'
|
||||
const method = isEditMode ? 'PUT' : 'POST'
|
||||
|
||||
// 調用 API 創建或更新獎項
|
||||
const response = await fetch(apiUrl, {
|
||||
method: method,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
@@ -1920,36 +1929,38 @@ export function CompetitionManagement() {
|
||||
const result = await response.json()
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(result.message || '創建獎項失敗')
|
||||
throw new Error(result.message || (isEditMode ? '更新獎項失敗' : '創建獎項失敗'))
|
||||
}
|
||||
|
||||
// 創建成功,添加到本地列表
|
||||
const newAwardItem = {
|
||||
id: result.data.id,
|
||||
// 創建或更新成功,處理本地列表
|
||||
const awardItem = {
|
||||
id: result.data.id || selectedAward.id,
|
||||
competitionId: newAward.competitionId,
|
||||
competitionName: competition.name,
|
||||
participantId: newAward.participantId,
|
||||
participantType: newAward.participantType,
|
||||
participantName: participantName,
|
||||
creatorName: creatorName,
|
||||
awardType: newAward.awardType,
|
||||
appId: actualParticipantType === "individual" ? newAward.participantId : (participant?.app_id || null),
|
||||
teamId: actualParticipantType === "team" ? newAward.participantId : null,
|
||||
appName: actualParticipantType === "individual" ? participantName : (participant?.app_name || null),
|
||||
teamName: actualParticipantType === "team" ? participantName : null,
|
||||
creator: creatorName,
|
||||
awardType: newAward.awardType as any,
|
||||
awardName: newAward.awardName,
|
||||
customAwardTypeId: newAward.customAwardTypeId,
|
||||
score: newAward.score,
|
||||
rank: newAward.rank,
|
||||
category: newAward.category,
|
||||
description: newAward.description,
|
||||
judgeComments: newAward.judgeComments,
|
||||
applicationLinks: newAward.applicationLinks,
|
||||
documents: newAward.documents,
|
||||
photos: newAward.photos,
|
||||
year: new Date().getFullYear(),
|
||||
month: new Date().getMonth() + 1,
|
||||
icon: icon,
|
||||
createdAt: new Date().toISOString(),
|
||||
customAwardTypeId: newAward.customAwardTypeId,
|
||||
competitionType: competition.type as any,
|
||||
rank: newAward.rank,
|
||||
category: newAward.category as any,
|
||||
}
|
||||
|
||||
addAward(newAwardItem)
|
||||
if (isEditMode) {
|
||||
// 編輯模式:更新現有獎項
|
||||
updateAward(awardItem)
|
||||
} else {
|
||||
// 創建模式:添加新獎項
|
||||
const { id, ...awardWithoutId } = awardItem
|
||||
addAward(awardWithoutId)
|
||||
}
|
||||
|
||||
// 重置表單
|
||||
setNewAward({
|
||||
@@ -1974,8 +1985,9 @@ export function CompetitionManagement() {
|
||||
})
|
||||
|
||||
setShowCreateAward(false)
|
||||
setSuccess("獎項創建成功!")
|
||||
setTimeout(() => setSuccess(""), 3000)
|
||||
setSelectedAward(null)
|
||||
setSuccess(isEditMode ? "獎項更新成功!" : "獎項創建成功!")
|
||||
setTimeout(() => setSuccess(""), 3000)
|
||||
|
||||
} catch (error) {
|
||||
console.error('創建獎項失敗:', error)
|
||||
@@ -1991,7 +2003,10 @@ export function CompetitionManagement() {
|
||||
id: award.id,
|
||||
competitionId: award.competitionId,
|
||||
awardName: award.award_name,
|
||||
hasCompetitionId: !!award.competitionId
|
||||
hasCompetitionId: !!award.competitionId,
|
||||
photos: award.photos,
|
||||
photosType: typeof award.photos,
|
||||
photosLength: award.photos?.length
|
||||
} : null
|
||||
});
|
||||
|
||||
@@ -2022,7 +2037,8 @@ export function CompetitionManagement() {
|
||||
}
|
||||
}
|
||||
|
||||
const handleEditAward = (award: any) => {
|
||||
const handleEditAward = async (award: any) => {
|
||||
console.log('🎯 開始編輯獎項:', award)
|
||||
setSelectedAward(award)
|
||||
setNewAward({
|
||||
competitionId: award.competitionId,
|
||||
@@ -2044,6 +2060,16 @@ export function CompetitionManagement() {
|
||||
judgeComments: (award as any).judgeComments || "",
|
||||
photos: (award as any).photos || [],
|
||||
})
|
||||
|
||||
// 載入對應競賽的評審和參賽者資料
|
||||
if (award.competitionId) {
|
||||
console.log('🔄 載入競賽資料,競賽ID:', award.competitionId)
|
||||
await loadCompetitionParticipants(award.competitionId)
|
||||
console.log('✅ 載入完成,評審數量:', competitionJudges.length)
|
||||
} else {
|
||||
console.log('❌ 獎項沒有 competitionId')
|
||||
}
|
||||
|
||||
setShowCreateAward(true)
|
||||
}
|
||||
|
||||
@@ -2056,16 +2082,36 @@ export function CompetitionManagement() {
|
||||
if (!awardToDelete) return
|
||||
|
||||
setIsLoading(true)
|
||||
await new Promise((resolve) => setTimeout(resolve, 500))
|
||||
|
||||
// 這裡應該調用 context 中的刪除函數
|
||||
// deleteAward(awardToDelete.id)
|
||||
|
||||
setShowDeleteAwardConfirm(false)
|
||||
setAwardToDelete(null)
|
||||
setSuccess("獎項刪除成功!")
|
||||
setIsLoading(false)
|
||||
setTimeout(() => setSuccess(""), 3000)
|
||||
try {
|
||||
// 調用 API 刪除獎項
|
||||
const response = await fetch(`/api/admin/awards/${awardToDelete.id}`, {
|
||||
method: 'DELETE',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
})
|
||||
|
||||
const result = await response.json()
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(result.message || '刪除獎項失敗')
|
||||
}
|
||||
|
||||
// 刪除成功,從本地列表移除
|
||||
deleteAward(awardToDelete.id)
|
||||
|
||||
setShowDeleteAwardConfirm(false)
|
||||
setAwardToDelete(null)
|
||||
setSuccess("獎項刪除成功!")
|
||||
setTimeout(() => setSuccess(""), 3000)
|
||||
|
||||
} catch (error) {
|
||||
console.error('刪除獎項失敗:', error)
|
||||
setError(error instanceof Error ? error.message : '刪除獎項失敗')
|
||||
} finally {
|
||||
setIsLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
const handleManualScoring = async (competition: any) => {
|
||||
@@ -4048,7 +4094,7 @@ export function CompetitionManagement() {
|
||||
return (
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4 min-h-[400px]">
|
||||
{paginatedAwards.map((award: any) => (
|
||||
<Card key={award.id} className="relative overflow-hidden hover:shadow-lg transition-shadow h-[280px] flex flex-col">
|
||||
<Card key={award.id} className="relative overflow-hidden hover:shadow-lg transition-shadow flex flex-col">
|
||||
<div className="absolute top-4 right-4 text-2xl">{award.icon}</div>
|
||||
<CardContent className="p-4 flex-grow flex flex-col justify-between">
|
||||
<div className="space-y-3 flex-grow">
|
||||
@@ -9127,36 +9173,63 @@ export function CompetitionManagement() {
|
||||
)}
|
||||
|
||||
{/* 得獎照片 */}
|
||||
{(selectedAward as any).photos && (selectedAward as any).photos.length > 0 && (
|
||||
<div className="space-y-3">
|
||||
<h4 className="text-lg font-semibold text-gray-900">得獎照片</h4>
|
||||
<div className="grid grid-cols-2 md:grid-cols-4 gap-4">
|
||||
{(selectedAward as any).photos.map((photo: any) => (
|
||||
<div key={photo.id} className="space-y-2">
|
||||
<div className="aspect-video bg-gray-100 rounded-lg border overflow-hidden">
|
||||
{photo.url ? (
|
||||
<img
|
||||
src={photo.url}
|
||||
alt={photo.caption || "得獎照片"}
|
||||
className="w-full h-full object-cover"
|
||||
onError={(e) => {
|
||||
e.currentTarget.style.display = 'none';
|
||||
e.currentTarget.nextElementSibling?.classList.remove('hidden');
|
||||
}}
|
||||
/>
|
||||
) : null}
|
||||
<div className="w-full h-full bg-gray-200 flex items-center justify-center text-2xl hidden">
|
||||
🖼️
|
||||
{(() => {
|
||||
const photos = (selectedAward as any)?.photos;
|
||||
console.log('🖼️ 檢查照片資料:', {
|
||||
hasPhotos: !!photos,
|
||||
photosType: typeof photos,
|
||||
photosLength: photos?.length,
|
||||
photosData: photos
|
||||
});
|
||||
|
||||
if (!photos || !Array.isArray(photos) || photos.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="space-y-3">
|
||||
<h4 className="text-lg font-semibold text-gray-900">得獎照片</h4>
|
||||
<div className="grid grid-cols-2 md:grid-cols-4 gap-4">
|
||||
{photos.map((photo: any, index: number) => {
|
||||
console.log('📸 處理照片:', { index, photo });
|
||||
return (
|
||||
<div key={photo.id || photo.url || index} className="space-y-2">
|
||||
<div className="aspect-video bg-gray-100 rounded-lg border overflow-hidden">
|
||||
{photo.url ? (
|
||||
<img
|
||||
src={photo.url}
|
||||
alt={photo.caption || photo.name || "得獎照片"}
|
||||
className="w-full h-full object-cover"
|
||||
onError={(e) => {
|
||||
console.log('❌ 圖片載入失敗:', photo.url);
|
||||
e.currentTarget.style.display = 'none';
|
||||
e.currentTarget.nextElementSibling?.classList.remove('hidden');
|
||||
}}
|
||||
onLoad={() => {
|
||||
console.log('✅ 圖片載入成功:', photo.url);
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<div className="w-full h-full bg-gray-200 flex items-center justify-center text-2xl">
|
||||
🖼️
|
||||
</div>
|
||||
)}
|
||||
<div className="w-full h-full bg-gray-200 flex items-center justify-center text-2xl hidden">
|
||||
🖼️
|
||||
</div>
|
||||
</div>
|
||||
{(photo.caption || photo.name) && (
|
||||
<p className="text-xs text-gray-600 text-center">
|
||||
{photo.caption || photo.name}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{photo.caption && (
|
||||
<p className="text-xs text-gray-600 text-center">{photo.caption}</p>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
);
|
||||
})()}
|
||||
|
||||
<div className="flex justify-end space-x-3 pt-4 border-t">
|
||||
<Button variant="outline" onClick={() => setShowAwardDetail(false)}>
|
||||
|
Reference in New Issue
Block a user