刪除不必要檔案、實作 AI 助手

This commit is contained in:
2025-09-19 03:24:09 +08:00
parent ea17bd0ca2
commit 08a1f1b248
32 changed files with 348 additions and 3292 deletions

View File

@@ -1,80 +0,0 @@
# 測試數據插入說明
## 問題修復
**已修復重複約束錯誤**:原來的腳本會因為同一個用戶對同一個應用重複評分而出現 `Duplicate entry` 錯誤。現在已修復為使用不同的用戶 ID。
**已修復 null 值錯誤**:修復了 `user_id` 不能為 null 的問題,提供了簡化版本的腳本。
## 腳本版本
### 版本 1完整版本 (`insert-test-data.sql`)
- 使用不同的用戶 ID 避免重複約束
- 需要資料庫中有至少 10 個活躍用戶
### 版本 2簡化版本 (`insert-test-data-simple.sql`)
- 使用單一用戶 ID避免 null 值問題
- 只需要資料庫中有至少 1 個活躍用戶
- 只有 1 條評分記錄
### 版本 3多用戶版本 (`insert-test-data-multi-user.sql`) ⭐ 推薦
- 使用 5 個不同用戶,避免重複約束
- 需要資料庫中有至少 5 個活躍用戶
- 包含 25 條瀏覽、8 條按讚、5 條評分記錄
- 平衡了數據豐富度和穩定性
## 方法一:使用 MySQL 命令行
1. 打開命令提示符或 PowerShell
2. 連接到 MySQL
```bash
mysql -u root -p
```
3. 選擇資料庫:
```sql
USE ai_showcase_platform;
```
4. 執行 SQL 腳本(推薦使用多用戶版本):
```sql
source E:/ai-showcase-platform/scripts/insert-test-data-multi-user.sql
```
## 方法二:使用 MySQL Workbench 或其他 GUI 工具
1. 打開 MySQL Workbench
2. 連接到您的 MySQL 服務器
3. 選擇 `ai_showcase_platform` 資料庫
4. 打開 `scripts/insert-test-data-multi-user.sql` 文件(推薦)
5. 執行整個腳本
## 方法三:使用 phpMyAdmin
1. 打開 phpMyAdmin
2. 選擇 `ai_showcase_platform` 資料庫
3. 點擊 "SQL" 標籤
4. 複製 `scripts/insert-test-data-multi-user.sql` 的內容(推薦)
5. 貼上並執行
## 預期結果
執行成功後,您應該看到:
- 25 條瀏覽記錄(使用 5 個不同用戶)
- 8 條按讚記錄(使用 5 個不同用戶)
- 5 條評分記錄(使用 5 個不同用戶)
- 應用統計數據更新為25 瀏覽、8 讚、4.2 平均評分
## 驗證
執行完成後,您可以:
1. 重新載入應用管理頁面
2. 點擊任何應用的「查看詳情」
3. 切換到「統計數據」標籤頁查看真實數據
4. 切換到「評價管理」標籤頁查看評價列表
## 注意事項
- 腳本會先清空現有的測試數據,避免重複
- **簡化版本**:使用單一用戶 ID只有 1 條評分記錄
- **多用戶版本**:使用 5 個不同用戶,平衡數據豐富度和穩定性 ⭐ 推薦
- **完整版本**:使用不同用戶 ID需要至少 10 個活躍用戶
- 如果您的資料庫中用戶數量少於 5 個,建議使用簡化版本

View File

@@ -1,72 +0,0 @@
// =====================================================
// 檢查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,69 +0,0 @@
// =====================================================
// 檢查競賽詳細數據
// =====================================================
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

@@ -1,60 +0,0 @@
// =====================================================
// 檢查競賽相關數據
// =====================================================
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();

View File

@@ -1,60 +0,0 @@
// =====================================================
// 檢查環境變數載入情況
// =====================================================
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

@@ -1,73 +0,0 @@
// =====================================================
// 檢查現有的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();

View File

@@ -1,32 +0,0 @@
// =====================================================
// 檢查服務器狀態腳本
// =====================================================
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

@@ -1,34 +0,0 @@
const mysql = require('mysql2/promise');
async function clearDatabase() {
const connection = await mysql.createConnection({
host: 'mysql.theaken.com',
port: 33306,
user: 'AI_Platform',
password: 'Aa123456',
database: 'db_AI_Platform'
});
console.log('🗑️ 清空資料庫...');
// 清空所有表(按依賴順序)
const tables = [
'app_judge_scores',
'competition_apps',
'competition_judges',
'apps',
'judges',
'competitions',
'users'
];
for (const table of tables) {
await connection.execute(`DELETE FROM ${table}`);
console.log(`✅ 清空了 ${table}`);
}
await connection.end();
console.log('🎉 資料庫清空完成!');
}
clearDatabase().catch(console.error);

View File

@@ -1,66 +0,0 @@
// =====================================================
// 創建團隊評分表
// =====================================================
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

@@ -1,66 +0,0 @@
// =====================================================
// 通過 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

@@ -1,18 +0,0 @@
-- 創建虛擬應用記錄用於團隊評分
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,83 +0,0 @@
// =====================================================
// 通過 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

@@ -1,71 +0,0 @@
// =====================================================
// 創建虛擬應用記錄用於團隊評分
// =====================================================
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,107 +0,0 @@
-- =====================================================
-- 修復外鍵約束問題的 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

@@ -1,319 +0,0 @@
#!/usr/bin/env node
// =====================================================
// 填充示例數據腳本
// =====================================================
const mysql = require('mysql2/promise');
const { v4: uuidv4 } = require('uuid');
// 資料庫配置
const dbConfig = {
host: process.env.DB_HOST || 'mysql.theaken.com',
port: parseInt(process.env.DB_PORT || '33306'),
user: process.env.DB_USER || 'AI_Platform',
password: process.env.DB_PASSWORD || 'Aa123456',
database: process.env.DB_NAME || 'db_AI_Platform',
charset: 'utf8mb4',
timezone: '+08:00',
};
async function populateSampleData() {
let connection;
try {
console.log('🚀 開始填充示例數據...');
// 創建連接
connection = await mysql.createConnection(dbConfig);
console.log('✅ 資料庫連接成功');
// 1. 創建示例用戶
console.log('👥 創建示例用戶...');
const users = [
{
id: uuidv4(),
name: '張小明',
email: 'zhang.xiaoming@company.com',
password_hash: '$2b$10$example.hash.here', // 示例哈希
department: 'HQBU',
role: 'developer',
join_date: '2024-01-15',
total_likes: 25,
total_views: 150,
is_active: true
},
{
id: uuidv4(),
name: '李美華',
email: 'li.meihua@company.com',
password_hash: '$2b$10$example.hash.here',
department: 'ITBU',
role: 'developer',
join_date: '2024-02-01',
total_likes: 18,
total_views: 120,
is_active: true
},
{
id: uuidv4(),
name: '王大偉',
email: 'wang.dawei@company.com',
password_hash: '$2b$10$example.hash.here',
department: 'MBU1',
role: 'developer',
join_date: '2024-01-20',
total_likes: 32,
total_views: 200,
is_active: true
},
{
id: uuidv4(),
name: '陳小芳',
email: 'chen.xiaofang@company.com',
password_hash: '$2b$10$example.hash.here',
department: 'SBU',
role: 'developer',
join_date: '2024-02-10',
total_likes: 15,
total_views: 90,
is_active: true
},
{
id: uuidv4(),
name: '劉志強',
email: 'liu.zhiqiang@company.com',
password_hash: '$2b$10$example.hash.here',
department: 'HQBU',
role: 'admin',
join_date: '2023-12-01',
total_likes: 5,
total_views: 50,
is_active: true
}
];
for (const user of users) {
await connection.execute(
`INSERT INTO users (id, name, email, password_hash, department, role, join_date, total_likes, total_views, status, created_at, updated_at)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NOW(), NOW())`,
[user.id, user.name, user.email, user.password_hash, user.department, user.role, user.join_date, user.total_likes, user.total_views, 'active']
);
}
console.log(`✅ 創建了 ${users.length} 個用戶`);
// 2. 創建示例評審
console.log('👨‍⚖️ 創建示例評審...');
const judges = [
{
id: uuidv4(),
name: '王教授',
title: '技術總監',
department: 'ITBU',
expertise: JSON.stringify(['AI', '機器學習', '深度學習']),
is_active: true
},
{
id: uuidv4(),
name: '李博士',
title: '產品經理',
department: 'HQBU',
expertise: JSON.stringify(['產品設計', '用戶體驗', '商業分析']),
is_active: true
},
{
id: uuidv4(),
name: '陳工程師',
title: '資深工程師',
department: 'MBU1',
expertise: JSON.stringify(['軟體開發', '系統架構', '資料庫']),
is_active: true
}
];
for (const judge of judges) {
await connection.execute(
`INSERT INTO judges (id, name, title, department, expertise, is_active, created_at, updated_at)
VALUES (?, ?, ?, ?, ?, ?, NOW(), NOW())`,
[judge.id, judge.name, judge.title, judge.department, judge.expertise, judge.is_active]
);
}
console.log(`✅ 創建了 ${judges.length} 個評審`);
// 3. 創建示例競賽
console.log('🏆 創建示例競賽...');
const competitions = [
{
id: uuidv4(),
name: '2024年AI創新競賽',
description: '展示最新的AI技術創新成果',
type: 'individual',
year: 2024,
month: 3,
start_date: '2024-03-01',
end_date: '2024-03-31',
status: 'active',
is_current: true,
is_active: true,
evaluation_focus: JSON.stringify(['創新性', '技術性', '實用性']),
max_team_size: 5
},
{
id: uuidv4(),
name: '2024年團隊協作競賽',
description: '團隊協作開發的AI應用',
type: 'team',
year: 2024,
month: 4,
start_date: '2024-04-01',
end_date: '2024-04-30',
status: 'upcoming',
is_current: false,
is_active: true,
evaluation_focus: JSON.stringify(['團隊協作', '技術實現', '創新應用']),
max_team_size: 8
}
];
for (const competition of competitions) {
await connection.execute(
`INSERT INTO competitions (id, name, description, type, year, month, start_date, end_date, status, is_current, is_active, evaluation_focus, max_team_size, created_at, updated_at)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NOW(), NOW())`,
[competition.id, competition.name, competition.description, competition.type, competition.year, competition.month,
competition.start_date, competition.end_date, competition.status, competition.is_current, competition.is_active,
competition.evaluation_focus, competition.max_team_size]
);
}
console.log(`✅ 創建了 ${competitions.length} 個競賽`);
// 4. 創建示例應用
console.log('📱 創建示例應用...');
const apps = [
{
id: uuidv4(),
name: '智能對話助手',
description: '基於大語言模型的智能對話系統',
creator_id: users[0].id,
team_id: null,
category: '文字處理',
technology_stack: JSON.stringify(['Python', 'OpenAI API', 'React']),
github_url: 'https://github.com/example/chatbot',
demo_url: 'https://demo.example.com/chatbot',
status: 'published',
is_active: true,
total_likes: 25,
total_views: 150
},
{
id: uuidv4(),
name: '圖像生成工具',
description: 'AI驅動的創意圖像生成平台',
creator_id: users[1].id,
team_id: null,
category: '圖像生成',
technology_stack: JSON.stringify(['Python', 'Stable Diffusion', 'FastAPI']),
github_url: 'https://github.com/example/image-gen',
demo_url: 'https://demo.example.com/image-gen',
status: 'published',
is_active: true,
total_likes: 18,
total_views: 120
},
{
id: uuidv4(),
name: '語音識別系統',
description: '高精度多語言語音識別服務',
creator_id: users[2].id,
team_id: null,
category: '語音辨識',
technology_stack: JSON.stringify(['Python', 'Whisper', 'Docker']),
github_url: 'https://github.com/example/speech-recognition',
demo_url: 'https://demo.example.com/speech',
status: 'published',
is_active: true,
total_likes: 32,
total_views: 200
}
];
for (const app of apps) {
await connection.execute(
`INSERT INTO apps (id, name, description, creator_id, team_id, category, type, app_url, likes_count, views_count, is_active, created_at, updated_at)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NOW(), NOW())`,
[app.id, app.name, app.description, app.creator_id, app.team_id, app.category, 'web', app.demo_url, app.total_likes, app.total_views, 1]
);
}
console.log(`✅ 創建了 ${apps.length} 個應用`);
// 5. 關聯競賽和應用
console.log('🔗 關聯競賽和應用...');
const currentCompetition = competitions[0]; // 當前競賽
for (const app of apps) {
await connection.execute(
`INSERT INTO competition_apps (id, competition_id, app_id, submitted_at) VALUES (?, ?, ?, NOW())`,
[uuidv4(), currentCompetition.id, app.id]
);
}
console.log(`✅ 關聯了 ${apps.length} 個應用到當前競賽`);
// 6. 關聯競賽和評審
console.log('🔗 關聯競賽和評審...');
for (const judge of judges) {
await connection.execute(
`INSERT INTO competition_judges (id, competition_id, judge_id, assigned_at) VALUES (?, ?, ?, NOW())`,
[uuidv4(), currentCompetition.id, judge.id]
);
}
console.log(`✅ 關聯了 ${judges.length} 個評審到當前競賽`);
// 7. 創建示例評分
console.log('📊 創建示例評分...');
for (const app of apps) {
for (const judge of judges) {
const scores = {
innovation_score: Math.floor(Math.random() * 5) + 1,
technical_score: Math.floor(Math.random() * 5) + 1,
usability_score: Math.floor(Math.random() * 5) + 1,
presentation_score: Math.floor(Math.random() * 5) + 1,
impact_score: Math.floor(Math.random() * 5) + 1
};
const totalScore = (scores.innovation_score + scores.technical_score + scores.usability_score +
scores.presentation_score + scores.impact_score) / 5;
await connection.execute(
`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 (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NOW())`,
[uuidv4(), judge.id, app.id, scores.innovation_score, scores.technical_score, scores.usability_score,
scores.presentation_score, scores.impact_score, totalScore, '示例評分']
);
}
}
console.log(`✅ 創建了 ${apps.length * judges.length} 個評分記錄`);
console.log('🎉 示例數據填充完成!');
console.log('\n📊 數據摘要:');
console.log(`- 用戶: ${users.length}`);
console.log(`- 評審: ${judges.length}`);
console.log(`- 競賽: ${competitions.length} 個 (其中 1 個為當前競賽)`);
console.log(`- 應用: ${apps.length}`);
console.log(`- 評分記錄: ${apps.length * judges.length}`);
} catch (error) {
console.error('❌ 填充失敗:', error.message);
console.error('詳細錯誤:', error);
process.exit(1);
} finally {
if (connection) {
await connection.end();
console.log('🔌 資料庫連接已關閉');
}
}
}
// 執行填充
if (require.main === module) {
populateSampleData().catch(console.error);
}
module.exports = { populateSampleData };

View File

@@ -1,22 +0,0 @@
-- =====================================================
-- 快速修復外鍵約束問題
-- =====================================================
-- 插入虛擬應用記錄
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,145 +0,0 @@
-- =====================================================
-- 重新設計評分數據庫架構
-- 讓評分系統完全基於 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

@@ -1,47 +0,0 @@
// 測試邀請連結生成
console.log('🧪 測試邀請連結生成...\n');
// 模擬環境變數
process.env.NEXT_PUBLIC_APP_URL = 'https://ai-showcase.company.com';
// 測試不同的環境變數設置
const testCases = [
{
name: '使用 NEXT_PUBLIC_APP_URL',
env: { NEXT_PUBLIC_APP_URL: 'https://ai-showcase.company.com' }
},
{
name: '未設置 NEXT_PUBLIC_APP_URL (使用 fallback)',
env: {}
},
{
name: '設置為空字符串 (使用 fallback)',
env: { NEXT_PUBLIC_APP_URL: '' }
}
];
testCases.forEach((testCase, index) => {
console.log(`${index + 1}. ${testCase.name}`);
// 設置環境變數
Object.keys(testCase.env).forEach(key => {
process.env[key] = testCase.env[key];
});
// 生成邀請連結
const invitationToken = 'test123456789';
const email = 'test@company.com';
const role = 'developer';
const invitationLink = `${process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:3000'}/register?token=${invitationToken}&email=${encodeURIComponent(email)}&role=${role}`;
console.log(` 邀請連結: ${invitationLink}`);
console.log(` 環境變數: NEXT_PUBLIC_APP_URL = ${process.env.NEXT_PUBLIC_APP_URL || 'undefined'}`);
console.log('');
});
console.log('✅ 測試完成!');
console.log('\n📝 說明:');
console.log('- 如果設置了 NEXT_PUBLIC_APP_URL將使用該值');
console.log('- 如果未設置或為空,將使用 fallback: http://localhost:3000');
console.log('- 在生產環境中,請確保設置正確的 NEXT_PUBLIC_APP_URL');

View File

@@ -1,51 +0,0 @@
// =====================================================
// 測試評分進度功能
// =====================================================
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

@@ -1,79 +0,0 @@
// =====================================================
// 測試評分完成度匯總功能
// =====================================================
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();