完成評審評分機制
This commit is contained in:
72
scripts/check-app-competition-relation.js
Normal file
72
scripts/check-app-competition-relation.js
Normal 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();
|
@@ -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);
|
69
scripts/check-competition-data-details.js
Normal file
69
scripts/check-competition-data-details.js
Normal 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();
|
60
scripts/check-competition-data.js
Normal file
60
scripts/check-competition-data.js
Normal 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
60
scripts/check-env.js
Normal 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 不存在');
|
||||
}
|
73
scripts/check-existing-apps.js
Normal file
73
scripts/check-existing-apps.js
Normal 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
32
scripts/check-server.js
Normal 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();
|
107
scripts/complete-virtual-apps-setup.sql
Normal file
107
scripts/complete-virtual-apps-setup.sql
Normal 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_%';
|
66
scripts/create-team-scores-table.js
Normal file
66
scripts/create-team-scores-table.js
Normal 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();
|
66
scripts/create-virtual-app-api.js
Normal file
66
scripts/create-virtual-app-api.js
Normal 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();
|
18
scripts/create-virtual-app-simple.sql
Normal file
18
scripts/create-virtual-app-simple.sql
Normal 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';
|
83
scripts/create-virtual-apps-api.js
Normal file
83
scripts/create-virtual-apps-api.js
Normal 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();
|
71
scripts/create-virtual-apps.js
Normal file
71
scripts/create-virtual-apps.js
Normal 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();
|
@@ -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);
|
107
scripts/fix-foreign-key-constraint.sql
Normal file
107
scripts/fix-foreign-key-constraint.sql
Normal 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';
|
54
scripts/manual-insert-virtual-apps.sql
Normal file
54
scripts/manual-insert-virtual-apps.sql
Normal 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_%';
|
||||
|
||||
-- 檢查外鍵約束是否解決
|
||||
-- 現在可以嘗試插入團隊評分記錄
|
68
scripts/migrate-to-dynamic-scoring.js
Normal file
68
scripts/migrate-to-dynamic-scoring.js
Normal 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
22
scripts/quick-fix.sql
Normal 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';
|
145
scripts/redesign-scoring-database.sql
Normal file
145
scripts/redesign-scoring-database.sql
Normal 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;
|
92
scripts/setup-competition-relations.js
Normal file
92
scripts/setup-competition-relations.js
Normal 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();
|
@@ -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();
|
41
scripts/simple-virtual-apps.sql
Normal file
41
scripts/simple-virtual-apps.sql
Normal 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';
|
@@ -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);
|
51
scripts/test-scoring-progress.js
Normal file
51
scripts/test-scoring-progress.js
Normal 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();
|
79
scripts/test-scoring-summary.js
Normal file
79
scripts/test-scoring-summary.js
Normal 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();
|
Reference in New Issue
Block a user