刪除不必要檔案、實作 AI 助手
This commit is contained in:
@@ -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 個,建議使用簡化版本
|
@@ -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();
|
@@ -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();
|
@@ -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();
|
@@ -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 不存在');
|
||||
}
|
@@ -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();
|
@@ -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();
|
@@ -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);
|
@@ -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();
|
@@ -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();
|
@@ -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';
|
@@ -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();
|
@@ -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();
|
@@ -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';
|
@@ -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 };
|
@@ -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';
|
@@ -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;
|
@@ -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');
|
@@ -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();
|
@@ -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();
|
Reference in New Issue
Block a user