修正評審連結問題、評審進度條異常
This commit is contained in:
@@ -12,7 +12,7 @@ export async function GET(request: NextRequest) {
|
|||||||
|
|
||||||
// 動態計算每個競賽的狀態
|
// 動態計算每個競賽的狀態
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
const competitionsWithCalculatedStatus = competitions.map(competition => {
|
const competitionsWithCalculatedStatus = await Promise.all(competitions.map(async (competition) => {
|
||||||
const startDate = new Date(competition.start_date);
|
const startDate = new Date(competition.start_date);
|
||||||
const endDate = new Date(competition.end_date);
|
const endDate = new Date(competition.end_date);
|
||||||
|
|
||||||
@@ -29,14 +29,26 @@ export async function GET(request: NextRequest) {
|
|||||||
} else if (nowUTC >= startDateUTC && nowUTC <= endDateUTC) {
|
} else if (nowUTC >= startDateUTC && nowUTC <= endDateUTC) {
|
||||||
calculatedStatus = 'active'; // 進行中
|
calculatedStatus = 'active'; // 進行中
|
||||||
} else if (nowUTC > endDateUTC) {
|
} else if (nowUTC > endDateUTC) {
|
||||||
calculatedStatus = 'completed'; // 已完成
|
// 競賽結束後,檢查評分進度
|
||||||
|
try {
|
||||||
|
const { ScoringService } = await import('@/lib/services/database-service');
|
||||||
|
const scoringProgress = await ScoringService.getCompetitionScoringProgress(competition.id);
|
||||||
|
if (scoringProgress.percentage >= 100) {
|
||||||
|
calculatedStatus = 'completed'; // 評分完成,競賽完成
|
||||||
|
} else {
|
||||||
|
calculatedStatus = 'judging'; // 評分未完成,仍在評審中
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('獲取評分進度失敗,使用預設狀態:', error);
|
||||||
|
calculatedStatus = 'judging'; // 無法獲取進度時,預設為評審中
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...competition,
|
...competition,
|
||||||
status: calculatedStatus
|
status: calculatedStatus
|
||||||
};
|
};
|
||||||
});
|
}));
|
||||||
|
|
||||||
// 計算統計數據
|
// 計算統計數據
|
||||||
const stats = {
|
const stats = {
|
||||||
|
@@ -366,8 +366,8 @@ export function ScoringManagement() {
|
|||||||
const selectedParticipant = competitionParticipants.find(p => p.id === manualScoring.participantId)
|
const selectedParticipant = competitionParticipants.find(p => p.id === manualScoring.participantId)
|
||||||
console.log('🔍 選中的參賽者:', selectedParticipant);
|
console.log('🔍 選中的參賽者:', selectedParticipant);
|
||||||
|
|
||||||
// 根據參賽者的實際類型確定 participantType
|
// 由於所有參賽者都是團隊的 app,所以 participantType 應該是 'app'
|
||||||
const participantType = selectedParticipant?.type === 'team' ? 'team' : 'app'
|
const participantType = 'app'
|
||||||
|
|
||||||
const requestData = {
|
const requestData = {
|
||||||
judgeId: manualScoring.judgeId,
|
judgeId: manualScoring.judgeId,
|
||||||
@@ -532,18 +532,33 @@ export function ScoringManagement() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (teamsData.success && teamsData.data && teamsData.data.teams) {
|
if (teamsData.success && teamsData.data && teamsData.data.teams) {
|
||||||
// 將每個團隊作為獨立的參賽項目(而不是團隊中的每個 app)
|
// 將每個團隊的每個 app 作為獨立的參賽項目
|
||||||
teamsData.data.teams.forEach((team: any) => {
|
teamsData.data.teams.forEach((team: any) => {
|
||||||
console.log('🔍 處理團隊:', team);
|
console.log('🔍 處理團隊:', team);
|
||||||
participants.push({
|
if (team.apps && team.apps.length > 0) {
|
||||||
id: team.id, // 使用團隊的 ID
|
team.apps.forEach((app: any) => {
|
||||||
name: team.name, // 團隊名稱
|
console.log('🔍 處理團隊 app:', app);
|
||||||
type: 'team',
|
participants.push({
|
||||||
teamName: team.name || '未知團隊', // 團隊名稱
|
id: app.id, // 使用 app 的 ID
|
||||||
displayName: team.name, // 顯示團隊名稱
|
name: app.name, // app 名稱
|
||||||
creator: team.members && team.members.find((m: any) => m.role === '隊長')?.name || '未知隊長',
|
type: 'team',
|
||||||
teamId: team.id // 保存團隊 ID
|
teamName: team.name || '未知團隊', // 團隊名稱
|
||||||
})
|
displayName: app.name, // 只顯示 app 名稱,團隊名稱通過 teamName 屬性獲取
|
||||||
|
creator: team.members && team.members.find((m: any) => m.role === '隊長')?.name || '未知隊長',
|
||||||
|
teamId: team.id // 保存團隊 ID
|
||||||
|
})
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
// 如果團隊沒有 app,仍然顯示團隊本身
|
||||||
|
participants.push({
|
||||||
|
id: team.id,
|
||||||
|
name: team.name,
|
||||||
|
type: 'team',
|
||||||
|
teamName: team.name || '未知團隊',
|
||||||
|
creator: team.members && team.members.find((m: any) => m.role === '隊長')?.name || '未知隊長',
|
||||||
|
teamId: team.id
|
||||||
|
})
|
||||||
|
}
|
||||||
})
|
})
|
||||||
console.log('✅ 團隊數據載入成功:', teamsData.data.teams.length, '個團隊')
|
console.log('✅ 團隊數據載入成功:', teamsData.data.teams.length, '個團隊')
|
||||||
} else {
|
} else {
|
||||||
|
@@ -1000,15 +1000,15 @@ export class JudgeService extends DatabaseServiceBase {
|
|||||||
a.name as display_name
|
a.name as display_name
|
||||||
FROM apps a
|
FROM apps a
|
||||||
INNER JOIN competition_apps ca ON a.id = ca.app_id
|
INNER JOIN competition_apps ca ON a.id = ca.app_id
|
||||||
LEFT JOIN app_judge_scores js ON a.id = js.app_id AND js.judge_id = ?
|
LEFT JOIN judge_scores js ON a.id = js.app_id AND js.judge_id = ? AND js.competition_id = ?
|
||||||
WHERE ca.competition_id = ? AND a.is_active = 1
|
WHERE ca.competition_id = ? AND a.is_active = 1
|
||||||
|
|
||||||
UNION ALL
|
UNION ALL
|
||||||
|
|
||||||
SELECT DISTINCT
|
SELECT DISTINCT
|
||||||
t.id,
|
a.id,
|
||||||
t.name,
|
a.name,
|
||||||
'team' as type,
|
'app' as type,
|
||||||
'team' as participant_type,
|
'team' as participant_type,
|
||||||
COALESCE(js.total_score, 0) as score,
|
COALESCE(js.total_score, 0) as score,
|
||||||
CASE
|
CASE
|
||||||
@@ -1017,15 +1017,16 @@ export class JudgeService extends DatabaseServiceBase {
|
|||||||
END as status,
|
END as status,
|
||||||
js.submitted_at,
|
js.submitted_at,
|
||||||
t.name as team_name,
|
t.name as team_name,
|
||||||
t.name as display_name
|
CONCAT(t.name, ' - ', a.name) as display_name
|
||||||
FROM teams t
|
FROM apps a
|
||||||
INNER JOIN competition_teams ct ON t.id = ct.team_id
|
INNER JOIN competition_teams ct ON a.team_id = ct.team_id
|
||||||
LEFT JOIN app_judge_scores js ON js.app_id = CONCAT('team_', t.id) AND js.judge_id = ?
|
LEFT JOIN teams t ON a.team_id = t.id
|
||||||
WHERE ct.competition_id = ? AND t.is_active = 1
|
LEFT JOIN judge_scores js ON a.id = js.app_id AND js.judge_id = ? AND js.competition_id = ?
|
||||||
|
WHERE ct.competition_id = ? AND a.is_active = 1
|
||||||
|
|
||||||
ORDER BY display_name
|
ORDER BY display_name
|
||||||
`;
|
`;
|
||||||
params = [judgeId, competitionId, judgeId, competitionId];
|
params = [judgeId, competitionId, competitionId, judgeId, competitionId, competitionId];
|
||||||
} else {
|
} else {
|
||||||
// 獲取所有競賽的任務
|
// 獲取所有競賽的任務
|
||||||
sql = `
|
sql = `
|
||||||
@@ -1044,7 +1045,7 @@ export class JudgeService extends DatabaseServiceBase {
|
|||||||
a.name as display_name
|
a.name as display_name
|
||||||
FROM apps a
|
FROM apps a
|
||||||
INNER JOIN competition_apps ca ON a.id = ca.app_id
|
INNER JOIN competition_apps ca ON a.id = ca.app_id
|
||||||
LEFT JOIN app_judge_scores js ON a.id = js.app_id AND js.judge_id = ?
|
LEFT JOIN judge_scores js ON a.id = js.app_id AND js.judge_id = ?
|
||||||
WHERE a.is_active = 1
|
WHERE a.is_active = 1
|
||||||
|
|
||||||
UNION ALL
|
UNION ALL
|
||||||
@@ -1065,7 +1066,7 @@ export class JudgeService extends DatabaseServiceBase {
|
|||||||
FROM apps a
|
FROM apps a
|
||||||
INNER JOIN competition_teams ct ON a.team_id = ct.team_id
|
INNER JOIN competition_teams ct ON a.team_id = ct.team_id
|
||||||
LEFT JOIN teams t ON a.team_id = t.id
|
LEFT JOIN teams t ON a.team_id = t.id
|
||||||
LEFT JOIN app_judge_scores js ON a.id = js.app_id AND js.judge_id = ?
|
LEFT JOIN judge_scores js ON a.id = js.app_id AND js.judge_id = ?
|
||||||
WHERE a.is_active = 1
|
WHERE a.is_active = 1
|
||||||
|
|
||||||
ORDER BY display_name
|
ORDER BY display_name
|
||||||
@@ -2019,7 +2020,7 @@ export class CompetitionService extends DatabaseServiceBase {
|
|||||||
ScoringService.getCompetitionRules(competitionId)
|
ScoringService.getCompetitionRules(competitionId)
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// 根據日期動態計算競賽狀態
|
// 根據日期和評分進度動態計算競賽狀態
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
const startDate = new Date(competition.start_date);
|
const startDate = new Date(competition.start_date);
|
||||||
const endDate = new Date(competition.end_date);
|
const endDate = new Date(competition.end_date);
|
||||||
@@ -2037,7 +2038,18 @@ export class CompetitionService extends DatabaseServiceBase {
|
|||||||
} else if (nowUTC >= startDateUTC && nowUTC <= endDateUTC) {
|
} else if (nowUTC >= startDateUTC && nowUTC <= endDateUTC) {
|
||||||
calculatedStatus = 'active'; // 進行中
|
calculatedStatus = 'active'; // 進行中
|
||||||
} else if (nowUTC > endDateUTC) {
|
} else if (nowUTC > endDateUTC) {
|
||||||
calculatedStatus = 'completed'; // 已完成
|
// 競賽結束後,檢查評分進度
|
||||||
|
try {
|
||||||
|
const scoringProgress = await ScoringService.getCompetitionScoringProgress(competitionId);
|
||||||
|
if (scoringProgress.percentage >= 100) {
|
||||||
|
calculatedStatus = 'completed'; // 評分完成,競賽完成
|
||||||
|
} else {
|
||||||
|
calculatedStatus = 'judging'; // 評分未完成,仍在評審中
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('獲取評分進度失敗,使用預設狀態:', error);
|
||||||
|
calculatedStatus = 'judging'; // 無法獲取進度時,預設為評審中
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 轉換字段名稱以匹配前端期望的格式
|
// 轉換字段名稱以匹配前端期望的格式
|
||||||
@@ -3877,114 +3889,52 @@ export class ScoringService extends DatabaseServiceBase {
|
|||||||
try {
|
try {
|
||||||
console.log('🔍 獲取競賽評分進度,competitionId:', competitionId);
|
console.log('🔍 獲取競賽評分進度,competitionId:', competitionId);
|
||||||
|
|
||||||
// 獲取競賽的評審數量
|
// 獲取競賽的參賽APP數量(從 competition_teams 與 apps 串聯)
|
||||||
const judgesResult = await DatabaseServiceBase.safeQuery(`
|
const appsResult = await DatabaseServiceBase.safeQuery(`
|
||||||
SELECT COUNT(DISTINCT cj.judge_id) as judge_count
|
SELECT COUNT(DISTINCT a.id) as app_count
|
||||||
FROM competition_judges cj
|
FROM competition_teams ct
|
||||||
WHERE cj.competition_id = ?
|
INNER JOIN apps a ON ct.team_id = a.team_id
|
||||||
|
WHERE ct.competition_id = ? AND a.is_active = 1
|
||||||
`, [competitionId]);
|
`, [competitionId]);
|
||||||
|
|
||||||
const judgeCount = judgesResult[0]?.judge_count || 0;
|
const appCount = appsResult[0]?.app_count || 0;
|
||||||
console.log('🔍 評審數量:', judgeCount);
|
console.log('🔍 參賽APP數量 (從 competition_teams):', appCount);
|
||||||
|
|
||||||
// 獲取競賽類型
|
// 獲取競賽的評分項目數量(從 competition_rules)
|
||||||
const competitionResult = await DatabaseServiceBase.safeQuery(`
|
const rulesResult = await DatabaseServiceBase.safeQuery(`
|
||||||
SELECT type FROM competitions WHERE id = ?
|
SELECT COUNT(*) as rule_count
|
||||||
|
FROM competition_rules
|
||||||
|
WHERE competition_id = ?
|
||||||
`, [competitionId]);
|
`, [competitionId]);
|
||||||
|
|
||||||
const competitionType = competitionResult[0]?.type || 'individual';
|
const ruleCount = rulesResult[0]?.rule_count || 0;
|
||||||
console.log('🔍 競賽類型:', competitionType);
|
console.log('🔍 評分項目數量:', ruleCount);
|
||||||
|
|
||||||
let participantCount = 0;
|
|
||||||
|
|
||||||
if (competitionType === 'team') {
|
|
||||||
// 團隊競賽:獲取參賽團隊數量
|
|
||||||
const teamsResult = await DatabaseServiceBase.safeQuery(`
|
|
||||||
SELECT COUNT(DISTINCT ct.team_id) as team_count
|
|
||||||
FROM competition_teams ct
|
|
||||||
WHERE ct.competition_id = ?
|
|
||||||
`, [competitionId]);
|
|
||||||
|
|
||||||
participantCount = teamsResult[0]?.team_count || 0;
|
|
||||||
console.log('🔍 參賽團隊數量:', participantCount);
|
|
||||||
} else {
|
|
||||||
// 個人競賽:獲取參賽APP數量
|
|
||||||
const appsResult = await DatabaseServiceBase.safeQuery(`
|
|
||||||
SELECT COUNT(DISTINCT ca.app_id) as app_count
|
|
||||||
FROM competition_apps ca
|
|
||||||
WHERE ca.competition_id = ?
|
|
||||||
`, [competitionId]);
|
|
||||||
|
|
||||||
participantCount = appsResult[0]?.app_count || 0;
|
|
||||||
console.log('🔍 參賽APP數量:', participantCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 如果沒有評審或參賽者關聯,嘗試從其他方式獲取
|
|
||||||
let finalJudgeCount = judgeCount;
|
|
||||||
let finalParticipantCount = participantCount;
|
|
||||||
|
|
||||||
if (judgeCount === 0) {
|
|
||||||
// 嘗試從 judges 表獲取所有評審
|
|
||||||
const allJudgesResult = await DatabaseServiceBase.safeQuery('SELECT COUNT(*) as judge_count FROM judges');
|
|
||||||
finalJudgeCount = allJudgesResult[0]?.judge_count || 0;
|
|
||||||
console.log('🔍 使用所有評審數量:', finalJudgeCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (participantCount === 0) {
|
|
||||||
if (competitionType === 'team') {
|
|
||||||
// 嘗試從 teams 表獲取所有團隊
|
|
||||||
const allTeamsResult = await DatabaseServiceBase.safeQuery('SELECT COUNT(*) as team_count FROM teams');
|
|
||||||
finalParticipantCount = allTeamsResult[0]?.team_count || 0;
|
|
||||||
console.log('🔍 使用所有團隊數量:', finalParticipantCount);
|
|
||||||
} else {
|
|
||||||
// 嘗試從 apps 表獲取所有APP
|
|
||||||
const allAppsResult = await DatabaseServiceBase.safeQuery('SELECT COUNT(*) as app_count FROM apps');
|
|
||||||
finalParticipantCount = allAppsResult[0]?.app_count || 0;
|
|
||||||
console.log('🔍 使用所有APP數量:', finalParticipantCount);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 獲取已完成的評分數量
|
// 獲取已完成的評分數量
|
||||||
let completedResult;
|
const completedResult = await DatabaseServiceBase.safeQuery(`
|
||||||
if (competitionType === 'team') {
|
SELECT COUNT(*) as completed_count
|
||||||
// 團隊競賽:查詢團隊評分記錄
|
FROM judge_scores js
|
||||||
completedResult = await DatabaseServiceBase.safeQuery(`
|
WHERE js.competition_id = ?
|
||||||
SELECT COUNT(*) as completed_count
|
`, [competitionId]);
|
||||||
FROM app_judge_scores js
|
|
||||||
WHERE js.app_id LIKE 'team_%'
|
|
||||||
AND EXISTS (
|
|
||||||
SELECT 1 FROM competition_teams ct
|
|
||||||
WHERE ct.competition_id = ?
|
|
||||||
AND js.app_id = CONCAT('team_', ct.team_id)
|
|
||||||
)
|
|
||||||
`, [competitionId]);
|
|
||||||
} else {
|
|
||||||
// 個人競賽:查詢應用評分記錄
|
|
||||||
completedResult = await DatabaseServiceBase.safeQuery(`
|
|
||||||
SELECT COUNT(*) as completed_count
|
|
||||||
FROM app_judge_scores js
|
|
||||||
WHERE js.app_id NOT LIKE 'team_%'
|
|
||||||
AND EXISTS (
|
|
||||||
SELECT 1 FROM competition_apps ca
|
|
||||||
WHERE ca.competition_id = ?
|
|
||||||
AND ca.app_id = js.app_id
|
|
||||||
)
|
|
||||||
`, [competitionId]);
|
|
||||||
}
|
|
||||||
|
|
||||||
const completed = completedResult[0]?.completed_count || 0;
|
const completed = completedResult[0]?.completed_count || 0;
|
||||||
const total = finalJudgeCount * finalParticipantCount;
|
|
||||||
|
// 計算總評分數:參賽APP數量 × 評分項目數量
|
||||||
|
const total = appCount * ruleCount;
|
||||||
|
|
||||||
|
// 計算進度百分比,確保不超過100%
|
||||||
const percentage = total > 0 ? Math.min(Math.round((completed / total) * 100), 100) : 0;
|
const percentage = total > 0 ? Math.min(Math.round((completed / total) * 100), 100) : 0;
|
||||||
|
|
||||||
console.log('🔍 評分進度結果:', {
|
console.log('🔍 進度計算詳情:', {
|
||||||
completed,
|
appCount,
|
||||||
|
ruleCount,
|
||||||
total,
|
total,
|
||||||
percentage,
|
completed,
|
||||||
judgeCount: finalJudgeCount,
|
percentage
|
||||||
participantCount: finalParticipantCount,
|
|
||||||
competitionType
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
console.log('🔍 評分進度結果:', { completed, total, percentage });
|
||||||
|
|
||||||
return {
|
return {
|
||||||
completed,
|
completed,
|
||||||
total,
|
total,
|
||||||
|
Reference in New Issue
Block a user