完成評審評分機制

This commit is contained in:
2025-09-18 18:34:31 +08:00
parent 2101767690
commit ffa1e45f63
54 changed files with 5730 additions and 709 deletions

View File

@@ -0,0 +1,72 @@
// =====================================================
// 檢查APP與競賽的關聯關係
// =====================================================
const mysql = require('mysql2/promise');
async function checkAppCompetitionRelation() {
console.log('🔍 檢查APP與競賽的關聯關係...\n');
try {
// 連接數據庫
const connection = await mysql.createConnection({
host: 'mysql.theaken.com',
port: 33306,
user: 'AI_Platform',
password: 'Aa123456',
database: 'db_AI_Platform'
});
console.log('✅ 數據庫連接成功');
// 檢查特定APP
const appId = "7f7395f4-ad9f-4d14-9e2c-84962ecbcfd7";
console.log(`\n📊 檢查APP ${appId}:`);
// 檢查APP是否存在
const [apps] = await connection.execute('SELECT * FROM apps WHERE id = ?', [appId]);
console.log('APP信息:', apps);
// 檢查APP的競賽關聯
const [competitionApps] = await connection.execute(
'SELECT ca.*, c.name as competition_name FROM competition_apps ca LEFT JOIN competitions c ON ca.competition_id = c.id WHERE ca.app_id = ?',
[appId]
);
console.log('競賽關聯:', competitionApps);
// 檢查所有競賽
console.log('\n📊 所有競賽:');
const [competitions] = await connection.execute('SELECT id, name, type FROM competitions');
console.log(competitions);
// 檢查所有競賽APP關聯
console.log('\n📊 所有競賽APP關聯:');
const [allCompetitionApps] = await connection.execute('SELECT * FROM competition_apps LIMIT 10');
console.log(allCompetitionApps);
// 如果沒有關聯,創建一個
if (competitionApps.length === 0 && apps.length > 0 && competitions.length > 0) {
console.log('\n🔧 創建APP與競賽的關聯...');
const competitionId = competitions[0].id;
try {
await connection.execute(
'INSERT INTO competition_apps (id, competition_id, app_id) VALUES (UUID(), ?, ?)',
[competitionId, appId]
);
console.log('✅ 關聯創建成功');
} catch (error) {
console.log('❌ 關聯創建失敗:', error.message);
}
}
await connection.end();
console.log('\n✅ 數據庫連接已關閉');
} catch (error) {
console.error('❌ 檢查失敗:', error.message);
}
}
// 執行檢查
checkAppCompetitionRelation();

View File

@@ -1,67 +0,0 @@
const mysql = require('mysql2/promise');
// 資料庫連接配置
const dbConfig = {
host: 'mysql.theaken.com',
port: 33306,
user: 'AI_Platform',
password: 'Aa123456',
database: 'db_AI_Platform',
charset: 'utf8mb4'
};
async function checkAppStatus() {
let connection;
try {
console.log('連接到資料庫...');
connection = await mysql.createConnection(dbConfig);
const appId = '7f7395f4-ad9f-4d14-9e2c-84962ecbcfd7';
// 檢查應用狀態
console.log('檢查應用狀態...');
const appSql = 'SELECT id, name, is_active FROM apps WHERE id = ?';
const appResult = await connection.execute(appSql, [appId]);
console.log('應用狀態:', appResult[0]);
// 檢查活動日誌
console.log('\n檢查活動日誌...');
const activitySql = 'SELECT * FROM activity_logs WHERE resource_id = ? ORDER BY created_at DESC LIMIT 3';
const activityResult = await connection.execute(activitySql, [appId]);
console.log('活動日誌:', activityResult[0]);
// 測試 JOIN 查詢
console.log('\n測試 JOIN 查詢...');
const joinSql = `
SELECT
a.*,
u.name as creator_name,
u.department as creator_department,
al.created_at as last_used,
al.details
FROM activity_logs al
JOIN apps a ON al.resource_id = a.id
LEFT JOIN users u ON a.creator_id = u.id
WHERE al.user_id = ?
AND al.action = 'view'
AND al.resource_type = 'app'
AND a.is_active = TRUE
ORDER BY al.created_at DESC
LIMIT ?
`;
const joinResult = await connection.execute(joinSql, ['7fbe6712-fcce-45b8-9889-608232161315', 10]);
console.log('JOIN 查詢結果:', joinResult[0]);
} catch (error) {
console.error('檢查過程中發生錯誤:', error);
} finally {
if (connection) {
await connection.end();
console.log('資料庫連接已關閉');
}
}
}
// 執行檢查
checkAppStatus().catch(console.error);

View File

@@ -0,0 +1,69 @@
// =====================================================
// 檢查競賽詳細數據
// =====================================================
const mysql = require('mysql2/promise');
async function checkCompetitionDataDetails() {
console.log('🔍 檢查競賽詳細數據...\n');
try {
// 連接數據庫
const connection = await mysql.createConnection({
host: 'mysql.theaken.com',
port: 33306,
user: 'AI_Platform',
password: 'Aa123456',
database: 'db_AI_Platform'
});
console.log('✅ 數據庫連接成功');
const competitionId = "be4b0a71-91f1-11f0-bb38-4adff2d0e33e";
// 檢查競賽評審關聯
console.log('\n📊 競賽評審關聯:');
const [competitionJudges] = await connection.execute(`
SELECT cj.*, j.name as judge_name
FROM competition_judges cj
LEFT JOIN judges j ON cj.judge_id = j.id
WHERE cj.competition_id = ?
`, [competitionId]);
console.log(competitionJudges);
// 檢查競賽APP關聯
console.log('\n📊 競賽APP關聯:');
const [competitionApps] = await connection.execute(`
SELECT ca.*, a.name as app_name
FROM competition_apps ca
LEFT JOIN apps a ON ca.app_id = a.id
WHERE ca.competition_id = ?
`, [competitionId]);
console.log(competitionApps);
// 檢查評分記錄
console.log('\n📊 評分記錄:');
const [judgeScores] = await connection.execute(`
SELECT js.*, j.name as judge_name, a.name as app_name
FROM judge_scores js
LEFT JOIN judges j ON js.judge_id = j.id
LEFT JOIN apps a ON js.app_id = a.id
WHERE js.competition_id = ?
`, [competitionId]);
console.log(judgeScores);
// 檢查所有競賽
console.log('\n📊 所有競賽:');
const [competitions] = await connection.execute('SELECT id, name FROM competitions');
console.log(competitions);
await connection.end();
console.log('\n✅ 數據庫連接已關閉');
} catch (error) {
console.error('❌ 檢查失敗:', error.message);
}
}
// 執行檢查
checkCompetitionDataDetails();

View File

@@ -0,0 +1,60 @@
// =====================================================
// 檢查競賽相關數據
// =====================================================
const mysql = require('mysql2/promise');
async function checkCompetitionData() {
console.log('🔍 檢查競賽相關數據...\n');
try {
// 連接數據庫
const connection = await mysql.createConnection({
host: 'mysql.theaken.com',
port: 33306,
user: 'AI_Platform',
password: 'Aa123456',
database: 'db_AI_Platform'
});
console.log('✅ 數據庫連接成功');
// 檢查競賽數據
console.log('\n📊 競賽數據:');
const [competitions] = await connection.execute('SELECT id, name, type FROM competitions LIMIT 5');
console.log(competitions);
// 檢查競賽規則
console.log('\n📊 競賽規則:');
const [rules] = await connection.execute('SELECT * FROM competition_rules LIMIT 10');
console.log(rules);
// 檢查競賽APP關聯
console.log('\n📊 競賽APP關聯:');
const [competitionApps] = await connection.execute('SELECT * FROM competition_apps LIMIT 10');
console.log(competitionApps);
// 檢查APP數據
console.log('\n📊 APP數據:');
const [apps] = await connection.execute('SELECT id, name, team_id FROM apps LIMIT 5');
console.log(apps);
// 檢查特定APP的競賽關聯
const appId = "7f7395f4-ad9f-4d14-9e2c-84962ecbcfd7";
console.log(`\n📊 APP ${appId} 的競賽關聯:`);
const [appCompetition] = await connection.execute(
'SELECT ca.*, c.name as competition_name FROM competition_apps ca LEFT JOIN competitions c ON ca.competition_id = c.id WHERE ca.app_id = ?',
[appId]
);
console.log(appCompetition);
await connection.end();
console.log('\n✅ 數據庫連接已關閉');
} catch (error) {
console.error('❌ 檢查失敗:', error.message);
}
}
// 執行檢查
checkCompetitionData();

60
scripts/check-env.js Normal file
View File

@@ -0,0 +1,60 @@
// =====================================================
// 檢查環境變數載入情況
// =====================================================
console.log('🔍 檢查環境變數載入情況...\n');
// 檢查所有相關的環境變數
const envVars = [
'DB_HOST',
'DB_PORT',
'DB_NAME',
'DB_USER',
'DB_PASSWORD',
'SLAVE_DB_HOST',
'SLAVE_DB_PORT',
'SLAVE_DB_NAME',
'SLAVE_DB_USER',
'SLAVE_DB_PASSWORD',
'DB_DUAL_WRITE_ENABLED',
'DB_MASTER_PRIORITY'
];
console.log('📋 環境變數檢查結果:');
console.log('='.repeat(50));
envVars.forEach(varName => {
const value = process.env[varName];
if (value) {
console.log(`${varName}: ${value}`);
} else {
console.log(`${varName}: undefined`);
}
});
console.log('\n🔍 檢查 .env 文件是否存在...');
const fs = require('fs');
const path = require('path');
const envPath = path.join(__dirname, '..', '.env');
if (fs.existsSync(envPath)) {
console.log('✅ .env 文件存在');
console.log('📄 .env 文件內容:');
console.log('-'.repeat(30));
const envContent = fs.readFileSync(envPath, 'utf8');
console.log(envContent);
} else {
console.log('❌ .env 文件不存在');
}
console.log('\n🔍 檢查 Next.js 配置...');
const nextConfigPath = path.join(__dirname, '..', 'next.config.mjs');
if (fs.existsSync(nextConfigPath)) {
console.log('✅ next.config.mjs 存在');
const nextConfig = fs.readFileSync(nextConfigPath, 'utf8');
console.log('📄 Next.js 配置內容:');
console.log('-'.repeat(30));
console.log(nextConfig);
} else {
console.log('❌ next.config.mjs 不存在');
}

View File

@@ -0,0 +1,73 @@
// =====================================================
// 檢查現有的APP記錄
// =====================================================
async function checkExistingApps() {
console.log('🔍 檢查現有的APP記錄...\n');
try {
// 等待服務器啟動
console.log('⏳ 等待服務器啟動...');
await new Promise(resolve => setTimeout(resolve, 5000));
try {
const response = await fetch('http://localhost:3000/api/competitions/be4b0a71-91f1-11f0-bb38-4adff2d0e33e/apps');
const data = await response.json();
console.log('\n📊 競賽APP列表:');
console.log('狀態碼:', response.status);
console.log('APP數量:', data.data?.apps?.length || 0);
if (data.data?.apps?.length > 0) {
console.log('\n📋 APP列表:');
data.data.apps.forEach((app, index) => {
console.log(`${index + 1}. ID: ${app.id}`);
console.log(` 名稱: ${app.name}`);
console.log(` 創建者: ${app.creator}`);
console.log(` 類型: ${app.type}`);
console.log('---');
});
} else {
console.log('❌ 沒有找到APP記錄');
}
} catch (error) {
console.log('❌ API 調用失敗:', error.message);
}
// 檢查團隊APP
try {
const response = await fetch('http://localhost:3000/api/competitions/be4b0a71-91f1-11f0-bb38-4adff2d0e33e/teams');
const data = await response.json();
console.log('\n📊 競賽團隊列表:');
console.log('狀態碼:', response.status);
console.log('團隊數量:', data.data?.teams?.length || 0);
if (data.data?.teams?.length > 0) {
console.log('\n📋 團隊列表:');
data.data.teams.forEach((team, index) => {
console.log(`${index + 1}. 團隊ID: ${team.id}`);
console.log(` 團隊名稱: ${team.name}`);
console.log(` 隊長: ${team.leader_name}`);
console.log(` APP數量: ${team.apps?.length || 0}`);
if (team.apps && team.apps.length > 0) {
team.apps.forEach((app, appIndex) => {
console.log(` APP ${appIndex + 1}: ${app.id} - ${app.name}`);
});
}
console.log('---');
});
} else {
console.log('❌ 沒有找到團隊記錄');
}
} catch (error) {
console.log('❌ 團隊API調用失敗:', error.message);
}
} catch (error) {
console.error('❌ 檢查失敗:', error.message);
}
}
// 執行檢查
checkExistingApps();

32
scripts/check-server.js Normal file
View File

@@ -0,0 +1,32 @@
// =====================================================
// 檢查服務器狀態腳本
// =====================================================
async function checkServer() {
console.log('🔍 檢查服務器狀態...\n');
try {
// 等待服務器啟動
console.log('⏳ 等待服務器啟動...');
await new Promise(resolve => setTimeout(resolve, 5000));
// 測試基本連接
console.log('🌐 測試基本連接...');
const response = await fetch('http://localhost:3000/api/test-db');
if (!response.ok) {
console.error('❌ 服務器回應錯誤:', response.status, response.statusText);
return;
}
const data = await response.json();
console.log('✅ 服務器正常運行');
console.log('📊 回應數據:', JSON.stringify(data, null, 2));
} catch (error) {
console.error('❌ 服務器連接失敗:', error.message);
console.log('\n💡 提示: 請確保開發服務器正在運行 (npm run dev)');
}
}
checkServer();

View File

@@ -0,0 +1,107 @@
-- =====================================================
-- 完整的虛擬應用設置腳本
-- =====================================================
-- 1. 查看現有團隊
SELECT '=== 現有團隊 ===' as info;
SELECT id, name, department FROM teams WHERE is_active = TRUE;
-- 2. 查看現有應用
SELECT '=== 現有應用 ===' as info;
SELECT id, name, type FROM apps WHERE is_active = TRUE LIMIT 5;
-- 3. 創建虛擬應用記錄
SELECT '=== 創建虛擬應用 ===' as info;
-- 為團隊 aaa 創建虛擬應用
INSERT IGNORE INTO apps (
id,
name,
description,
creator_id,
category,
type,
app_url,
icon,
icon_color,
likes_count,
views_count,
rating,
is_active,
created_at,
updated_at
) VALUES (
'team_t1757702332911zcl6iafq1',
'[團隊評分] aaa',
'團隊 aaa 的評分記錄 - 用於存儲團隊評分數據',
'00000000-0000-0000-0000-000000000000',
'team_scoring',
'team',
NULL,
'Users',
'from-gray-500 to-gray-600',
0,
0,
0.00,
TRUE,
NOW(),
NOW()
);
-- 4. 驗證虛擬應用創建
SELECT '=== 虛擬應用創建結果 ===' as info;
SELECT id, name, type, category, is_active FROM apps WHERE id LIKE 'team_%';
-- 5. 測試插入團隊評分記錄
SELECT '=== 測試團隊評分插入 ===' as info;
-- 插入測試評分記錄
INSERT INTO app_judge_scores (
id,
judge_id,
app_id,
innovation_score,
technical_score,
usability_score,
presentation_score,
impact_score,
total_score,
comments,
submitted_at
) VALUES (
UUID(),
'fed0a353-8ffe-11f0-bb38-4adff2d0e33e', -- 評審ID
'team_t1757702332911zcl6iafq1', -- 虛擬應用ID
8, -- innovation_score
7, -- technical_score
9, -- usability_score
8, -- presentation_score
7, -- impact_score
7.8, -- total_score (平均分)
'測試團隊評分記錄',
NOW()
);
-- 6. 驗證評分記錄插入
SELECT '=== 評分記錄插入結果 ===' as info;
SELECT
ajs.id,
ajs.judge_id,
ajs.app_id,
ajs.innovation_score,
ajs.technical_score,
ajs.usability_score,
ajs.presentation_score,
ajs.impact_score,
ajs.total_score,
ajs.comments,
ajs.submitted_at,
a.name as app_name
FROM app_judge_scores ajs
LEFT JOIN apps a ON ajs.app_id = a.id
WHERE ajs.app_id LIKE 'team_%'
ORDER BY ajs.submitted_at DESC;
-- 7. 清理測試數據(可選)
-- DELETE FROM app_judge_scores WHERE app_id LIKE 'team_%';
-- DELETE FROM apps WHERE id LIKE 'team_%';

View File

@@ -0,0 +1,66 @@
// =====================================================
// 創建團隊評分表
// =====================================================
const mysql = require('mysql2/promise');
async function createTeamScoresTable() {
console.log('🔧 創建團隊評分表...\n');
try {
// 連接資料庫
const connection = await mysql.createConnection({
host: process.env.DB_HOST || '122.100.99.161',
port: parseInt(process.env.DB_PORT || '43306'),
user: process.env.DB_USER || 'AI_Platform',
password: process.env.DB_PASSWORD || 'Aa123456',
database: process.env.DB_NAME || 'db_AI_Platform'
});
console.log('✅ 資料庫連接成功');
// 創建團隊評分表
const createTableSQL = `
CREATE TABLE IF NOT EXISTS team_judge_scores (
id VARCHAR(36) PRIMARY KEY,
judge_id VARCHAR(36) NOT NULL,
team_id VARCHAR(36) NOT NULL,
innovation_score INT NOT NULL CHECK (innovation_score >= 1 AND innovation_score <= 10),
technical_score INT NOT NULL CHECK (technical_score >= 1 AND technical_score <= 10),
usability_score INT NOT NULL CHECK (usability_score >= 1 AND usability_score <= 10),
presentation_score INT NOT NULL CHECK (presentation_score >= 1 AND presentation_score <= 10),
impact_score INT NOT NULL CHECK (impact_score >= 1 AND impact_score <= 10),
total_score DECIMAL(5,2) NOT NULL,
comments TEXT,
submitted_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (judge_id) REFERENCES judges(id) ON DELETE CASCADE,
FOREIGN KEY (team_id) REFERENCES teams(id) ON DELETE CASCADE,
UNIQUE KEY unique_judge_team (judge_id, team_id),
INDEX idx_judge (judge_id),
INDEX idx_team (team_id),
INDEX idx_total_score (total_score)
)
`;
await connection.execute(createTableSQL);
console.log('✅ 團隊評分表創建成功');
// 檢查表是否創建成功
const [tables] = await connection.execute("SHOW TABLES LIKE 'team_judge_scores'");
if (tables.length > 0) {
console.log('✅ 表存在確認成功');
} else {
console.log('❌ 表創建失敗');
}
await connection.end();
console.log('\n✅ 團隊評分表創建完成!');
} catch (error) {
console.error('❌ 創建表失敗:', error.message);
}
}
// 執行創建
createTeamScoresTable();

View File

@@ -0,0 +1,66 @@
// =====================================================
// 通過 API 創建虛擬應用記錄
// =====================================================
async function createVirtualApp() {
console.log('🔧 通過 API 創建虛擬應用記錄...\n');
try {
// 等待服務器啟動
console.log('⏳ 等待服務器啟動...');
await new Promise(resolve => setTimeout(resolve, 5000));
// 創建虛擬應用記錄
const virtualAppData = {
id: 'team_t1757702332911zcl6iafq1',
name: '[團隊評分] aaa',
description: '團隊 aaa 的評分記錄',
creator_id: '00000000-0000-0000-0000-000000000000',
category: 'team_scoring',
type: 'team',
app_url: null,
icon: 'Users',
icon_color: 'from-gray-500 to-gray-600',
likes_count: 0,
views_count: 0,
rating: 0.00,
is_active: true
};
console.log('📝 創建虛擬應用數據:');
console.log(JSON.stringify(virtualAppData, null, 2));
try {
const response = await fetch('http://localhost:3000/api/apps', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(virtualAppData)
});
const data = await response.json();
console.log('\n📊 API 回應:');
console.log('狀態碼:', response.status);
console.log('回應數據:', JSON.stringify(data, null, 2));
if (data.success) {
console.log('✅ 虛擬應用創建成功!');
} else {
console.log('❌ 虛擬應用創建失敗:', data.message);
if (data.error) {
console.log('錯誤詳情:', data.error);
}
}
} catch (error) {
console.log('❌ API 調用失敗:', error.message);
}
} catch (error) {
console.error('❌ 測試失敗:', error.message);
}
}
// 執行創建
createVirtualApp();

View File

@@ -0,0 +1,18 @@
-- 創建虛擬應用記錄用於團隊評分
INSERT IGNORE INTO apps (
id, name, description, creator_id, category, type,
app_url, icon, icon_color, likes_count, views_count,
rating, is_active, created_at, updated_at
) VALUES (
'team_t1757702332911zcl6iafq1',
'[團隊評分] aaa',
'團隊 aaa 的評分記錄',
'00000000-0000-0000-0000-000000000000',
'team_scoring',
'team',
NULL, 'Users', 'from-gray-500 to-gray-600',
0, 0, 0.00, TRUE, NOW(), NOW()
);
-- 驗證創建結果
SELECT id, name, type FROM apps WHERE id = 'team_t1757702332911zcl6iafq1';

View File

@@ -0,0 +1,83 @@
// =====================================================
// 通過 API 創建虛擬應用記錄
// =====================================================
async function createVirtualAppsViaAPI() {
console.log('🔧 通過 API 創建虛擬應用記錄...\n');
try {
// 等待服務器啟動
console.log('⏳ 等待服務器啟動...');
await new Promise(resolve => setTimeout(resolve, 3000));
// 獲取團隊數據
console.log('📋 獲取團隊數據...');
const teamsResponse = await fetch('http://localhost:3000/api/competitions');
const competitionsData = await teamsResponse.json();
if (!competitionsData.success || !competitionsData.data || competitionsData.data.length === 0) {
console.log('❌ 無法獲取競賽數據');
return;
}
const competition = competitionsData.data[0];
console.log('🎯 選擇競賽:', competition.name);
// 獲取競賽的團隊數據
const teamsDataResponse = await fetch(`http://localhost:3000/api/competitions/${competition.id}/teams`);
const teamsData = await teamsDataResponse.json();
if (!teamsData.success || !teamsData.data.teams || teamsData.data.teams.length === 0) {
console.log('❌ 競賽沒有團隊數據');
return;
}
const teams = teamsData.data.teams;
console.log('✅ 獲取到', teams.length, '個團隊');
// 為每個團隊創建虛擬應用
for (const team of teams) {
const virtualAppData = {
name: `[團隊評分] ${team.name}`,
description: `團隊 ${team.name} 的評分記錄`,
creator_id: '00000000-0000-0000-0000-000000000000', // 虛擬創建者ID
category: 'team_scoring',
type: 'team',
app_url: null,
icon: 'Users',
icon_color: 'from-gray-500 to-gray-600'
};
console.log(`📝 創建虛擬應用: ${team.name}...`);
try {
const response = await fetch('http://localhost:3000/api/apps', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(virtualAppData)
});
const data = await response.json();
if (data.success) {
console.log(`✅ 虛擬應用創建成功: ${data.app?.id || '未知ID'}`);
} else {
console.log(`⚠️ 虛擬應用創建失敗: ${data.message}`);
}
} catch (error) {
console.log(`❌ 創建虛擬應用時出錯: ${error.message}`);
}
}
console.log('\n✅ 虛擬應用記錄創建完成!');
} catch (error) {
console.error('❌ 創建虛擬應用失敗:', error.message);
console.log('\n💡 提示: 請確保開發服務器正在運行 (npm run dev)');
}
}
// 執行創建
createVirtualAppsViaAPI();

View File

@@ -0,0 +1,71 @@
// =====================================================
// 創建虛擬應用記錄用於團隊評分
// =====================================================
const mysql = require('mysql2/promise');
async function createVirtualApps() {
console.log('🔧 創建虛擬應用記錄...\n');
try {
// 連接資料庫
const connection = await mysql.createConnection({
host: process.env.DB_HOST || '122.100.99.161',
port: parseInt(process.env.DB_PORT || '43306'),
user: process.env.DB_USER || 'AI_Platform',
password: process.env.DB_PASSWORD || 'Aa123456',
database: process.env.DB_NAME || 'db_AI_Platform'
});
console.log('✅ 資料庫連接成功');
// 獲取所有團隊
const [teams] = await connection.execute('SELECT id, name FROM teams WHERE is_active = TRUE');
console.log('📋 找到', teams.length, '個團隊');
// 為每個團隊創建虛擬應用
for (const team of teams) {
const virtualAppId = `team_${team.id}`;
// 檢查是否已存在
const [existing] = await connection.execute('SELECT id FROM apps WHERE id = ?', [virtualAppId]);
if (existing.length === 0) {
const sql = `
INSERT INTO apps (id, name, description, creator_id, category, type, app_url, icon, icon_color, likes_count, views_count, rating, is_active, created_at, updated_at)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NOW(), NOW())
`;
const params = [
virtualAppId,
`[團隊評分] ${team.name}`,
`團隊 ${team.name} 的評分記錄`,
'00000000-0000-0000-0000-000000000000', // 虛擬創建者ID
'team_scoring',
'team',
null,
'Users',
'from-gray-500 to-gray-600',
0,
0,
0.00,
true
];
await connection.execute(sql, params);
console.log(`✅ 創建虛擬應用: ${virtualAppId} (${team.name})`);
} else {
console.log(`⏭️ 虛擬應用已存在: ${virtualAppId}`);
}
}
await connection.end();
console.log('\n✅ 虛擬應用記錄創建完成!');
} catch (error) {
console.error('❌ 創建虛擬應用失敗:', error.message);
}
}
// 執行創建
createVirtualApps();

View File

@@ -1,92 +0,0 @@
const mysql = require('mysql2/promise');
// 資料庫連接配置
const dbConfig = {
host: 'mysql.theaken.com',
port: 33306,
user: 'AI_Platform',
password: 'Aa123456',
database: 'db_AI_Platform',
charset: 'utf8mb4'
};
async function fixFavoritesDuplicates() {
let connection;
try {
console.log('連接到資料庫...');
connection = await mysql.createConnection(dbConfig);
console.log('檢查重複的收藏記錄...');
// 查找重複記錄
const [duplicates] = await connection.execute(`
SELECT user_id, app_id, COUNT(*) as count
FROM user_favorites
GROUP BY user_id, app_id
HAVING COUNT(*) > 1
`);
if (duplicates.length === 0) {
console.log('沒有發現重複的收藏記錄');
return;
}
console.log(`發現 ${duplicates.length} 組重複記錄:`);
for (const duplicate of duplicates) {
console.log(`用戶 ${duplicate.user_id} 對應用 ${duplicate.app_id}${duplicate.count} 條記錄`);
// 保留最早的記錄,刪除其他重複記錄
const [records] = await connection.execute(`
SELECT id, created_at
FROM user_favorites
WHERE user_id = ? AND app_id = ?
ORDER BY created_at ASC
`, [duplicate.user_id, duplicate.app_id]);
if (records.length > 1) {
// 保留第一條記錄,刪除其他記錄
const keepRecord = records[0];
const deleteIds = records.slice(1).map(r => r.id);
console.log(`保留記錄 ID: ${keepRecord.id} (創建時間: ${keepRecord.created_at})`);
console.log(`刪除記錄 IDs: ${deleteIds.join(', ')}`);
await connection.execute(`
DELETE FROM user_favorites
WHERE id IN (${deleteIds.map(() => '?').join(',')})
`, deleteIds);
console.log(`已清理 ${deleteIds.length} 條重複記錄`);
}
}
console.log('重複記錄清理完成!');
// 驗證修復結果
const [remainingDuplicates] = await connection.execute(`
SELECT user_id, app_id, COUNT(*) as count
FROM user_favorites
GROUP BY user_id, app_id
HAVING COUNT(*) > 1
`);
if (remainingDuplicates.length === 0) {
console.log('✅ 所有重複記錄已成功清理');
} else {
console.log('❌ 仍有重複記錄存在:', remainingDuplicates);
}
} catch (error) {
console.error('修復過程中發生錯誤:', error);
} finally {
if (connection) {
await connection.end();
console.log('資料庫連接已關閉');
}
}
}
// 執行修復
fixFavoritesDuplicates().catch(console.error);

View File

@@ -0,0 +1,107 @@
-- =====================================================
-- 修復外鍵約束問題的 SQL 腳本
-- =====================================================
-- 問題app_judge_scores 表的 app_id 外鍵約束失敗
-- 原因:團隊評分使用的 teamId 不存在於 apps 表中
-- 解決方案:為團隊創建對應的虛擬應用記錄
-- 1. 先查看現有的團隊數據
SELECT '=== 現有團隊 ===' as info;
SELECT id, name, department FROM teams WHERE is_active = TRUE;
-- 2. 為團隊 t1757702332911zcl6iafq1 (aaa) 創建虛擬應用
INSERT IGNORE INTO apps (
id,
name,
description,
creator_id,
category,
type,
app_url,
icon,
icon_color,
likes_count,
views_count,
rating,
is_active,
created_at,
updated_at
) VALUES (
'team_t1757702332911zcl6iafq1',
'[團隊評分] aaa',
'團隊 aaa 的評分記錄 - 用於存儲團隊評分數據',
'00000000-0000-0000-0000-000000000000',
'team_scoring',
'team',
NULL,
'Users',
'from-gray-500 to-gray-600',
0,
0,
0.00,
TRUE,
NOW(),
NOW()
);
-- 3. 驗證虛擬應用是否創建成功
SELECT '=== 虛擬應用創建結果 ===' as info;
SELECT id, name, type, category, is_active FROM apps WHERE id = 'team_t1757702332911zcl6iafq1';
-- 4. 現在可以插入團隊評分記錄了
-- 測試插入團隊評分使用真實的評審ID
INSERT INTO app_judge_scores (
id,
judge_id,
app_id,
innovation_score,
technical_score,
usability_score,
presentation_score,
impact_score,
total_score,
comments,
submitted_at
) VALUES (
UUID(),
'fed0a353-8ffe-11f0-bb38-4adff2d0e33e', -- 評審ID
'team_t1757702332911zcl6iafq1', -- 虛擬應用ID
8, -- innovation_score
7, -- technical_score
9, -- usability_score
8, -- presentation_score
7, -- impact_score
7.8, -- total_score (平均分)
'測試團隊評分記錄',
NOW()
);
-- 5. 驗證評分記錄是否插入成功
SELECT '=== 評分記錄插入結果 ===' as info;
SELECT
ajs.id,
ajs.judge_id,
ajs.app_id,
ajs.innovation_score,
ajs.technical_score,
ajs.usability_score,
ajs.presentation_score,
ajs.impact_score,
ajs.total_score,
ajs.comments,
ajs.submitted_at,
a.name as app_name
FROM app_judge_scores ajs
LEFT JOIN apps a ON ajs.app_id = a.id
WHERE ajs.app_id = 'team_t1757702332911zcl6iafq1'
ORDER BY ajs.submitted_at DESC;
-- 6. 如果有其他團隊,也需要創建對應的虛擬應用
-- 格式team_{teamId}
-- 例如team_另一個團隊ID
-- 7. 清理測試數據(可選)
-- DELETE FROM app_judge_scores WHERE app_id = 'team_t1757702332911zcl6iafq1';
-- DELETE FROM apps WHERE id = 'team_t1757702332911zcl6iafq1';

View File

@@ -0,0 +1,54 @@
-- =====================================================
-- 手動新增虛擬應用記錄用於團隊評分
-- =====================================================
-- 首先查看現有的團隊數據
SELECT id, name FROM teams WHERE is_active = TRUE;
-- 為每個團隊創建對應的虛擬應用記錄
-- 格式team_{teamId} 以便識別這是團隊評分
-- 團隊 1: aaa (ID: t1757702332911zcl6iafq1)
INSERT INTO apps (
id,
name,
description,
creator_id,
category,
type,
app_url,
icon,
icon_color,
likes_count,
views_count,
rating,
is_active,
created_at,
updated_at
) VALUES (
'team_t1757702332911zcl6iafq1',
'[團隊評分] aaa',
'團隊 aaa 的評分記錄',
'00000000-0000-0000-0000-000000000000',
'team_scoring',
'team',
NULL,
'Users',
'from-gray-500 to-gray-600',
0,
0,
0.00,
TRUE,
NOW(),
NOW()
);
-- 如果有其他團隊,請按照相同格式添加
-- 團隊 2: (如果有的話)
-- INSERT INTO apps (...) VALUES (...);
-- 驗證插入結果
SELECT id, name, type, category FROM apps WHERE id LIKE 'team_%';
-- 檢查外鍵約束是否解決
-- 現在可以嘗試插入團隊評分記錄

View File

@@ -0,0 +1,68 @@
// =====================================================
// 遷移到動態評分系統的腳本
// =====================================================
const mysql = require('mysql2/promise');
const fs = require('fs');
async function migrateToDynamicScoring() {
console.log('🚀 開始遷移到動態評分系統...\n');
let connection;
try {
// 連接數據庫
connection = await mysql.createConnection({
host: 'mysql.theaken.com',
port: 33306,
user: 'AI_Platform',
password: 'Aa123456',
database: 'db_AI_Platform'
});
console.log('✅ 數據庫連接成功');
// 讀取 SQL 腳本
const sqlScript = fs.readFileSync('scripts/redesign-scoring-database.sql', 'utf8');
// 分割 SQL 語句
const statements = sqlScript
.split(';')
.map(stmt => stmt.trim())
.filter(stmt => stmt.length > 0 && !stmt.startsWith('--'));
console.log(`📝 準備執行 ${statements.length} 個 SQL 語句...`);
// 逐個執行 SQL 語句
for (let i = 0; i < statements.length; i++) {
const statement = statements[i];
console.log(`\n🔄 執行語句 ${i + 1}/${statements.length}:`);
console.log(statement.substring(0, 100) + (statement.length > 100 ? '...' : ''));
try {
await connection.execute(statement);
console.log('✅ 執行成功');
} catch (error) {
console.log('⚠️ 執行警告:', error.message);
// 繼續執行其他語句
}
}
console.log('\n🎉 數據庫遷移完成!');
console.log('\n📊 新表結構:');
console.log('- judge_scores: 主評分記錄表');
console.log('- judge_score_details: 評分項目詳情表');
console.log('- app_judge_scores: 向後兼容視圖');
} catch (error) {
console.error('❌ 遷移失敗:', error.message);
} finally {
if (connection) {
await connection.end();
console.log('\n✅ 數據庫連接已關閉');
}
}
}
// 執行遷移
migrateToDynamicScoring();

22
scripts/quick-fix.sql Normal file
View File

@@ -0,0 +1,22 @@
-- =====================================================
-- 快速修復外鍵約束問題
-- =====================================================
-- 插入虛擬應用記錄
INSERT IGNORE INTO apps (
id, name, description, creator_id, category, type,
app_url, icon, icon_color, likes_count, views_count,
rating, is_active, created_at, updated_at
) VALUES (
'team_t1757702332911zcl6iafq1',
'[團隊評分] aaa',
'團隊 aaa 的評分記錄',
'00000000-0000-0000-0000-000000000000',
'team_scoring',
'team',
NULL, 'Users', 'from-gray-500 to-gray-600',
0, 0, 0.00, TRUE, NOW(), NOW()
);
-- 驗證創建結果
SELECT id, name, type FROM apps WHERE id = 'team_t1757702332911zcl6iafq1';

View File

@@ -0,0 +1,145 @@
-- =====================================================
-- 重新設計評分數據庫架構
-- 讓評分系統完全基於 competition_rules 的動態內容
-- =====================================================
-- 1. 創建新的評分記錄表(基於競賽規則)
CREATE TABLE `judge_scores` (
`id` VARCHAR(36) PRIMARY KEY,
`judge_id` VARCHAR(36) NOT NULL,
`app_id` VARCHAR(36) NOT NULL,
`competition_id` VARCHAR(36) NOT NULL,
`total_score` DECIMAL(5,2) NOT NULL,
`comments` TEXT,
`submitted_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (`judge_id`) REFERENCES `judges`(`id`) ON DELETE CASCADE,
FOREIGN KEY (`app_id`) REFERENCES `apps`(`id`) ON DELETE CASCADE,
FOREIGN KEY (`competition_id`) REFERENCES `competitions`(`id`) ON DELETE CASCADE,
UNIQUE KEY `unique_judge_app_competition` (`judge_id`, `app_id`, `competition_id`),
INDEX `idx_judge` (`judge_id`),
INDEX `idx_app` (`app_id`),
INDEX `idx_competition` (`competition_id`),
INDEX `idx_total_score` (`total_score`)
);
-- 2. 創建評分項目詳情表(存儲具體的評分項目和分數)
CREATE TABLE `judge_score_details` (
`id` VARCHAR(36) PRIMARY KEY,
`judge_score_id` VARCHAR(36) NOT NULL,
`rule_id` VARCHAR(36) NOT NULL,
`rule_name` VARCHAR(200) NOT NULL,
`score` INT NOT NULL CHECK (`score` >= 1 AND `score` <= 10),
`weight` DECIMAL(5,2) NOT NULL DEFAULT 0.00,
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (`judge_score_id`) REFERENCES `judge_scores`(`id`) ON DELETE CASCADE,
FOREIGN KEY (`rule_id`) REFERENCES `competition_rules`(`id`) ON DELETE CASCADE,
UNIQUE KEY `unique_score_rule` (`judge_score_id`, `rule_id`),
INDEX `idx_judge_score` (`judge_score_id`),
INDEX `idx_rule` (`rule_id`)
);
-- 3. 備份現有的 app_judge_scores 數據(如果需要)
CREATE TABLE `app_judge_scores_backup` AS SELECT * FROM `app_judge_scores`;
-- 4. 遷移現有數據到新結構
INSERT INTO `judge_scores` (
`id`, `judge_id`, `app_id`, `competition_id`, `total_score`, `comments`, `submitted_at`
)
SELECT
`id`,
`judge_id`,
`app_id`,
COALESCE(
(SELECT ca.competition_id FROM competition_apps ca WHERE ca.app_id = ajs.app_id LIMIT 1),
'unknown-competition'
) as competition_id,
`total_score`,
`comments`,
`submitted_at`
FROM `app_judge_scores` ajs;
-- 5. 遷移評分詳情數據
INSERT INTO `judge_score_details` (
`id`, `judge_score_id`, `rule_id`, `rule_name`, `score`, `weight`
)
SELECT
UUID() as id,
ajs.id as judge_score_id,
'migration-innovation' as rule_id,
'創新程度' as rule_name,
ajs.innovation_score as score,
20.00 as weight
FROM `app_judge_scores` ajs
WHERE ajs.innovation_score > 0
UNION ALL
SELECT
UUID() as id,
ajs.id as judge_score_id,
'migration-technical' as rule_id,
'技術實現' as rule_name,
ajs.technical_score as score,
20.00 as weight
FROM `app_judge_scores` ajs
WHERE ajs.technical_score > 0
UNION ALL
SELECT
UUID() as id,
ajs.id as judge_score_id,
'migration-usability' as rule_id,
'實用性' as rule_name,
ajs.usability_score as score,
20.00 as weight
FROM `app_judge_scores` ajs
WHERE ajs.usability_score > 0
UNION ALL
SELECT
UUID() as id,
ajs.id as judge_score_id,
'migration-presentation' as rule_id,
'展示效果' as rule_name,
ajs.presentation_score as score,
20.00 as weight
FROM `app_judge_scores` ajs
WHERE ajs.presentation_score > 0
UNION ALL
SELECT
UUID() as id,
ajs.id as judge_score_id,
'migration-impact' as rule_id,
'影響力' as rule_name,
ajs.impact_score as score,
20.00 as weight
FROM `app_judge_scores` ajs
WHERE ajs.impact_score > 0;
-- 6. 刪除舊的 app_judge_scores 表
-- DROP TABLE `app_judge_scores`;
-- 7. 創建視圖以保持向後兼容性
CREATE VIEW `app_judge_scores` AS
SELECT
js.id,
js.judge_id,
js.app_id,
js.total_score,
js.comments,
js.submitted_at,
-- 動態生成評分字段(基於競賽規則)
COALESCE(MAX(CASE WHEN jsd.rule_name = '創新程度' THEN jsd.score END), 0) as innovation_score,
COALESCE(MAX(CASE WHEN jsd.rule_name = '技術實現' THEN jsd.score END), 0) as technical_score,
COALESCE(MAX(CASE WHEN jsd.rule_name = '實用性' THEN jsd.score END), 0) as usability_score,
COALESCE(MAX(CASE WHEN jsd.rule_name = '展示效果' THEN jsd.score END), 0) as presentation_score,
COALESCE(MAX(CASE WHEN jsd.rule_name = '影響力' THEN jsd.score END), 0) as impact_score
FROM `judge_scores` js
LEFT JOIN `judge_score_details` jsd ON js.id = jsd.judge_score_id
GROUP BY js.id, js.judge_id, js.app_id, js.total_score, js.comments, js.submitted_at;

View File

@@ -0,0 +1,92 @@
// =====================================================
// 設置競賽關聯數據
// =====================================================
const mysql = require('mysql2/promise');
async function setupCompetitionRelations() {
console.log('🔧 設置競賽關聯數據...\n');
try {
// 連接數據庫
const connection = await mysql.createConnection({
host: 'mysql.theaken.com',
port: 33306,
user: 'AI_Platform',
password: 'Aa123456',
database: 'db_AI_Platform'
});
console.log('✅ 數據庫連接成功');
const competitionId = "be4b0a71-91f1-11f0-bb38-4adff2d0e33e";
// 檢查現有的評審
console.log('\n📊 檢查現有評審...');
const [judges] = await connection.execute('SELECT id, name FROM judges LIMIT 5');
console.log('現有評審:', judges);
// 檢查現有的APP
console.log('\n📱 檢查現有APP...');
const [apps] = await connection.execute('SELECT id, name FROM apps LIMIT 5');
console.log('現有APP:', apps);
// 檢查現有的關聯
console.log('\n🔗 檢查現有關聯...');
const [existingJudges] = await connection.execute(
'SELECT COUNT(*) as count FROM competition_judges WHERE competition_id = ?',
[competitionId]
);
const [existingApps] = await connection.execute(
'SELECT COUNT(*) as count FROM competition_apps WHERE competition_id = ?',
[competitionId]
);
console.log('競賽評審關聯數:', existingJudges[0].count);
console.log('競賽APP關聯數:', existingApps[0].count);
// 如果沒有關聯,創建一些測試關聯
if (existingJudges[0].count === 0 && judges.length > 0) {
console.log('\n 創建評審關聯...');
for (let i = 0; i < Math.min(3, judges.length); i++) {
await connection.execute(
'INSERT INTO competition_judges (competition_id, judge_id) VALUES (?, ?)',
[competitionId, judges[i].id]
);
console.log(`✅ 關聯評審: ${judges[i].name}`);
}
}
if (existingApps[0].count === 0 && apps.length > 0) {
console.log('\n 創建APP關聯...');
for (let i = 0; i < Math.min(2, apps.length); i++) {
await connection.execute(
'INSERT INTO competition_apps (competition_id, app_id) VALUES (?, ?)',
[competitionId, apps[i].id]
);
console.log(`✅ 關聯APP: ${apps[i].name}`);
}
}
// 驗證關聯
console.log('\n✅ 驗證關聯...');
const [finalJudges] = await connection.execute(
'SELECT COUNT(*) as count FROM competition_judges WHERE competition_id = ?',
[competitionId]
);
const [finalApps] = await connection.execute(
'SELECT COUNT(*) as count FROM competition_apps WHERE competition_id = ?',
[competitionId]
);
console.log('最終評審關聯數:', finalJudges[0].count);
console.log('最終APP關聯數:', finalApps[0].count);
await connection.end();
console.log('\n✅ 數據庫連接已關閉');
} catch (error) {
console.error('❌ 設置失敗:', error.message);
}
}
// 執行設置
setupCompetitionRelations();

View File

@@ -1,28 +0,0 @@
const mysql = require('mysql2/promise');
async function simpleCheck() {
try {
const connection = await mysql.createConnection({
host: 'localhost',
user: 'root',
password: '123456',
database: 'ai_showcase_platform'
});
console.log('✅ 資料庫連接成功');
// 檢查 user_ratings 表
const [ratings] = await connection.execute('SELECT * FROM user_ratings LIMIT 5');
console.log('📊 user_ratings 數據:', ratings);
// 檢查 apps 表
const [apps] = await connection.execute('SELECT id, name FROM apps LIMIT 3');
console.log('📱 apps 數據:', apps);
await connection.end();
} catch (error) {
console.error('❌ 錯誤:', error.message);
}
}
simpleCheck();

View File

@@ -0,0 +1,41 @@
-- =====================================================
-- 簡化版虛擬應用插入腳本
-- =====================================================
-- 插入虛擬應用記錄用於團隊評分
INSERT IGNORE INTO apps (
id,
name,
description,
creator_id,
category,
type,
app_url,
icon,
icon_color,
likes_count,
views_count,
rating,
is_active,
created_at,
updated_at
) VALUES (
'team_t1757702332911zcl6iafq1',
'[團隊評分] aaa',
'團隊 aaa 的評分記錄',
'00000000-0000-0000-0000-000000000000',
'team_scoring',
'team',
NULL,
'Users',
'from-gray-500 to-gray-600',
0,
0,
0.00,
TRUE,
NOW(),
NOW()
);
-- 驗證插入結果
SELECT id, name, type FROM apps WHERE id = 'team_t1757702332911zcl6iafq1';

View File

@@ -1,86 +0,0 @@
const mysql = require('mysql2/promise');
// 資料庫連接配置
const dbConfig = {
host: 'mysql.theaken.com',
port: 33306,
user: 'AI_Platform',
password: 'Aa123456',
database: 'db_AI_Platform',
charset: 'utf8mb4'
};
async function testFavorites() {
let connection;
try {
console.log('連接到資料庫...');
connection = await mysql.createConnection(dbConfig);
// 測試添加收藏
const testUserId = 'test-user-123';
const testAppId = 'test-app-456';
console.log('測試添加收藏...');
// 先清理可能存在的測試數據
await connection.execute(
'DELETE FROM user_favorites WHERE user_id = ? AND app_id = ?',
[testUserId, testAppId]
);
// 第一次添加收藏
const favoriteId1 = require('crypto').randomUUID();
await connection.execute(`
INSERT INTO user_favorites (id, user_id, app_id, created_at)
VALUES (?, ?, ?, NOW())
`, [favoriteId1, testUserId, testAppId]);
console.log('✅ 第一次添加收藏成功');
// 檢查是否已收藏
const [checkResult] = await connection.execute(`
SELECT COUNT(*) as count
FROM user_favorites
WHERE user_id = ? AND app_id = ?
`, [testUserId, testAppId]);
console.log(`收藏記錄數量: ${checkResult[0].count}`);
// 嘗試重複添加收藏(應該失敗)
try {
const favoriteId2 = require('crypto').randomUUID();
await connection.execute(`
INSERT INTO user_favorites (id, user_id, app_id, created_at)
VALUES (?, ?, ?, NOW())
`, [favoriteId2, testUserId, testAppId]);
console.log('❌ 重複添加收藏應該失敗但成功了');
} catch (error) {
if (error.code === 'ER_DUP_ENTRY') {
console.log('✅ 重複添加收藏正確地被阻止');
} else {
console.log('❌ 重複添加收藏失敗,但錯誤類型不正確:', error.message);
}
}
// 清理測試數據
await connection.execute(
'DELETE FROM user_favorites WHERE user_id = ? AND app_id = ?',
[testUserId, testAppId]
);
console.log('✅ 測試數據已清理');
} catch (error) {
console.error('測試過程中發生錯誤:', error);
} finally {
if (connection) {
await connection.end();
console.log('資料庫連接已關閉');
}
}
}
// 執行測試
testFavorites().catch(console.error);

View File

@@ -0,0 +1,51 @@
// =====================================================
// 測試評分進度功能
// =====================================================
async function testScoringProgress() {
console.log('🔧 測試評分進度功能...\n');
try {
// 等待服務器啟動
console.log('⏳ 等待服務器啟動...');
await new Promise(resolve => setTimeout(resolve, 5000));
// 獲取競賽列表
console.log('📊 獲取競賽列表...');
const competitionsResponse = await fetch('http://localhost:3000/api/competitions');
const competitionsData = await competitionsResponse.json();
if (!competitionsData.success || !competitionsData.data || competitionsData.data.length === 0) {
console.log('❌ 沒有找到競賽數據');
return;
}
const competition = competitionsData.data[0];
console.log('✅ 找到競賽:', competition.name, '(ID:', competition.id + ')');
// 測試評分進度 API
console.log('\n📊 測試評分進度 API...');
const progressResponse = await fetch(`http://localhost:3000/api/competitions/scoring-progress?competitionId=${competition.id}`);
const progressData = await progressResponse.json();
console.log('📊 評分進度 API 回應:');
console.log('狀態碼:', progressResponse.status);
console.log('回應數據:', JSON.stringify(progressData, null, 2));
if (progressData.success) {
console.log('✅ 評分進度獲取成功!');
console.log(`📈 評分進度: ${progressData.data.completed}/${progressData.data.total} (${progressData.data.percentage}%)`);
} else {
console.log('❌ 評分進度獲取失敗:', progressData.message);
if (progressData.error) {
console.log('錯誤詳情:', progressData.error);
}
}
} catch (error) {
console.error('❌ 測試失敗:', error.message);
}
}
// 執行測試
testScoringProgress();

View File

@@ -0,0 +1,79 @@
// =====================================================
// 測試評分完成度匯總功能
// =====================================================
async function testScoringSummary() {
console.log('🔧 測試評分完成度匯總功能...\n');
try {
// 等待服務器啟動
console.log('⏳ 等待服務器啟動...');
await new Promise(resolve => setTimeout(resolve, 5000));
// 獲取競賽列表
console.log('📊 獲取競賽列表...');
const competitionsResponse = await fetch('http://localhost:3000/api/competitions');
const competitionsData = await competitionsResponse.json();
if (!competitionsData.success || !competitionsData.data || competitionsData.data.length === 0) {
console.log('❌ 沒有找到競賽數據');
return;
}
const competition = competitionsData.data[0];
console.log('✅ 找到競賽:', competition.name, '(ID:', competition.id + ')');
// 測試評分完成度匯總 API
console.log('\n📊 測試評分完成度匯總 API...');
const summaryResponse = await fetch(`http://localhost:3000/api/admin/scoring/summary?competitionId=${competition.id}`);
const summaryData = await summaryResponse.json();
console.log('📊 評分完成度匯總 API 回應:');
console.log('狀態碼:', summaryResponse.status);
console.log('回應數據:', JSON.stringify(summaryData, null, 2));
if (summaryData.success) {
console.log('✅ 評分完成度匯總獲取成功!');
const { judges, apps, overallStats } = summaryData.data;
console.log('\n📈 總體統計:');
console.log(`- 評審總數: ${overallStats.totalJudges}`);
console.log(`- 參賽APP數: ${overallStats.totalApps}`);
console.log(`- 已完成評分: ${overallStats.completedScores}`);
console.log(`- 總完成率: ${overallStats.overallCompletionRate}%`);
console.log('\n👨 評審完成度:');
judges.forEach((judge, index) => {
console.log(`${index + 1}. ${judge.name} (${judge.email})`);
console.log(` - 完成度: ${judge.completedCount}/${judge.totalCount} (${judge.completionRate}%)`);
console.log(` - 狀態: ${judge.status}`);
if (judge.lastScoredAt) {
console.log(` - 最後評分時間: ${judge.lastScoredAt}`);
}
});
console.log('\n📱 參賽APP完成度:');
apps.forEach((app, index) => {
console.log(`${index + 1}. ${app.name}${app.teamName ? ` (團隊: ${app.teamName})` : ''}`);
console.log(` - 完成度: ${app.scoredCount}/${app.totalJudges} 評審 (${app.completionRate}%)`);
console.log(` - 狀態: ${app.status}`);
if (app.averageScore) {
console.log(` - 平均分: ${app.averageScore}`);
}
});
} else {
console.log('❌ 評分完成度匯總獲取失敗:', summaryData.message);
if (summaryData.error) {
console.log('錯誤詳情:', summaryData.error);
}
}
} catch (error) {
console.error('❌ 測試失敗:', error.message);
}
}
// 執行測試
testScoringSummary();