From 08a1f1b248f3f7d0b97a4809839e1e3d5ef9e439 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=90=B3=E4=BD=A9=E5=BA=AD?= Date: Fri, 19 Sep 2025 03:24:09 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=AA=E9=99=A4=E4=B8=8D=E5=BF=85=E8=A6=81?= =?UTF-8?q?=E6=AA=94=E6=A1=88=E3=80=81=E5=AF=A6=E4=BD=9C=20AI=20=E5=8A=A9?= =?UTF-8?q?=E6=89=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README-DATABASE-FAILOVER.md | 275 ------------------- README-DATABASE.md | 222 --------------- README-DUAL-WRITE-SYNC.md | 237 ---------------- README-ENV.md | 56 ---- README-SCORING-BACKEND.md | 195 ------------- README-SCORING.md | 123 --------- SCORING-FORM-COMPLETE-FIX.md | 133 --------- SCORING-FORM-DEBUG.md | 147 ---------- SCORING-FORM-FINAL-FIX.md | 177 ------------ SCORING-FORM-FIX.md | 118 -------- components/chat-bot.tsx | 150 ++++++---- lib/ai-knowledge-base.ts | 253 +++++++++++++++++ scripts/README.md | 80 ------ scripts/check-app-competition-relation.js | 72 ----- scripts/check-competition-data-details.js | 69 ----- scripts/check-competition-data.js | 60 ---- scripts/check-env.js | 60 ---- scripts/check-existing-apps.js | 73 ----- scripts/check-server.js | 32 --- scripts/clear-database.js | 34 --- scripts/create-team-scores-table.js | 66 ----- scripts/create-virtual-app-api.js | 66 ----- scripts/create-virtual-app-simple.sql | 18 -- scripts/create-virtual-apps-api.js | 83 ------ scripts/create-virtual-apps.js | 71 ----- scripts/fix-foreign-key-constraint.sql | 107 -------- scripts/populate-sample-data.js | 319 ---------------------- scripts/quick-fix.sql | 22 -- scripts/redesign-scoring-database.sql | 145 ---------- scripts/test-invitation-link.js | 47 ---- scripts/test-scoring-progress.js | 51 ---- scripts/test-scoring-summary.js | 79 ------ 32 files changed, 348 insertions(+), 3292 deletions(-) delete mode 100644 README-DATABASE-FAILOVER.md delete mode 100644 README-DATABASE.md delete mode 100644 README-DUAL-WRITE-SYNC.md delete mode 100644 README-ENV.md delete mode 100644 README-SCORING-BACKEND.md delete mode 100644 README-SCORING.md delete mode 100644 SCORING-FORM-COMPLETE-FIX.md delete mode 100644 SCORING-FORM-DEBUG.md delete mode 100644 SCORING-FORM-FINAL-FIX.md delete mode 100644 SCORING-FORM-FIX.md create mode 100644 lib/ai-knowledge-base.ts delete mode 100644 scripts/README.md delete mode 100644 scripts/check-app-competition-relation.js delete mode 100644 scripts/check-competition-data-details.js delete mode 100644 scripts/check-competition-data.js delete mode 100644 scripts/check-env.js delete mode 100644 scripts/check-existing-apps.js delete mode 100644 scripts/check-server.js delete mode 100644 scripts/clear-database.js delete mode 100644 scripts/create-team-scores-table.js delete mode 100644 scripts/create-virtual-app-api.js delete mode 100644 scripts/create-virtual-app-simple.sql delete mode 100644 scripts/create-virtual-apps-api.js delete mode 100644 scripts/create-virtual-apps.js delete mode 100644 scripts/fix-foreign-key-constraint.sql delete mode 100644 scripts/populate-sample-data.js delete mode 100644 scripts/quick-fix.sql delete mode 100644 scripts/redesign-scoring-database.sql delete mode 100644 scripts/test-invitation-link.js delete mode 100644 scripts/test-scoring-progress.js delete mode 100644 scripts/test-scoring-summary.js diff --git a/README-DATABASE-FAILOVER.md b/README-DATABASE-FAILOVER.md deleted file mode 100644 index 16fac26..0000000 --- a/README-DATABASE-FAILOVER.md +++ /dev/null @@ -1,275 +0,0 @@ -# 資料庫備援系統說明 - -## 概述 - -本系統實現了主機和備機資料庫的自動備援機制,當主機資料庫出現問題時,系統會自動切換到備機資料庫,確保服務的連續性和穩定性。 - -## 功能特點 - -- ✅ 自動故障檢測和切換 -- ✅ 健康檢查機制 -- ✅ 手動切換功能 -- ✅ 資料同步功能 -- ✅ 監控面板 -- ✅ 連接池管理 -- ✅ 重試機制 - -## 環境變數配置 - -在 `.env` 文件中添加以下配置: - -```env -# ===== 主機資料庫配置 ===== -DB_HOST=mysql.theaken.com -DB_PORT=33306 -DB_NAME=db_AI_Platform -DB_USER=AI_Platform -DB_PASSWORD=Aa123456 - -# ===== 備機資料庫配置 ===== -SLAVE_DB_HOST=122.100.99.161 -SLAVE_DB_PORT=43306 -SLAVE_DB_NAME=db_nighttime_care_record -SLAVE_DB_USER=A999 -SLAVE_DB_PASSWORD=1023 - -# ===== 資料庫備援配置 ===== -DB_FAILOVER_ENABLED=true -DB_HEALTH_CHECK_INTERVAL=30000 -DB_CONNECTION_TIMEOUT=5000 -DB_RETRY_ATTEMPTS=3 -DB_RETRY_DELAY=2000 -``` - -## 初始化步驟 - -### 1. 初始化備機資料庫 - -首先在備機上創建資料庫結構: - -```bash -# 初始化備機資料庫結構 -pnpm run db:init-slave -``` - -### 2. 同步資料 - -將主機的資料同步到備機: - -```bash -# 同步所有資料 -pnpm run db:sync -``` - -### 3. 檢查健康狀態 - -檢查主機和備機的連接狀態: - -```bash -# 檢查資料庫健康狀態 -pnpm run db:health -``` - -## 使用方法 - -### 程式碼中使用 - -系統會自動使用備援功能,無需修改現有程式碼: - -```typescript -import { db } from '@/lib/database'; - -// 查詢資料 -const users = await db.query('SELECT * FROM users'); - -// 插入資料 -await db.insert('INSERT INTO users (name, email) VALUES (?, ?)', ['John', 'john@example.com']); - -// 獲取備援狀態 -const status = db.getFailoverStatus(); -console.log('當前使用資料庫:', status?.currentDatabase); - -// 手動切換資料庫 -await db.switchDatabase('slave'); // 切換到備機 -await db.switchDatabase('master'); // 切換到主機 -``` - -### 監控面板 - -訪問管理後台查看資料庫狀態: - -```typescript -import { DatabaseMonitor } from '@/components/admin/database-monitor'; - -// 在管理頁面中使用 - -``` - -### API 端點 - -#### 獲取資料庫狀態 - -```http -GET /api/admin/database-status -``` - -回應: -```json -{ - "success": true, - "data": { - "isEnabled": true, - "currentDatabase": "master", - "masterHealthy": true, - "slaveHealthy": true, - "lastHealthCheck": "2024-01-01T12:00:00.000Z", - "consecutiveFailures": 0, - "uptime": 3600, - "timestamp": "2024-01-01T12:00:00.000Z" - } -} -``` - -#### 切換資料庫 - -```http -POST /api/admin/database-status -Content-Type: application/json - -{ - "action": "switch", - "database": "slave" -} -``` - -## 腳本命令 - -| 命令 | 說明 | -|------|------| -| `pnpm run db:init-slave` | 初始化備機資料庫結構 | -| `pnpm run db:sync` | 同步主機資料到備機 | -| `pnpm run db:health` | 檢查資料庫健康狀態 | -| `pnpm run db:monitor` | 執行健康檢查並顯示結果 | - -## 故障處理 - -### 自動切換 - -當主機資料庫出現以下問題時,系統會自動切換到備機: - -- 連接超時 -- 連接重置 -- 協議錯誤 -- 其他連接相關錯誤 - -### 手動切換 - -如果需要手動切換資料庫: - -1. 通過監控面板切換 -2. 通過 API 切換 -3. 通過程式碼切換 - -### 故障恢復 - -當主機資料庫恢復後: - -1. 系統會自動檢測到主機恢復 -2. 可以手動切換回主機 -3. 建議重新同步資料 - -## 監控和日誌 - -### 健康檢查 - -- 每 30 秒自動檢查一次 -- 檢查連接狀態和響應時間 -- 記錄連續失敗次數 - -### 日誌記錄 - -系統會記錄以下事件: - -- 資料庫切換事件 -- 連接失敗事件 -- 健康檢查結果 -- 同步操作結果 - -### 監控指標 - -- 當前使用的資料庫 -- 主機和備機的健康狀態 -- 最後檢查時間 -- 連續失敗次數 -- 系統運行時間 - -## 注意事項 - -1. **資料一致性**:備機資料可能不是實時同步的,建議定期同步 -2. **性能影響**:備援機制會增加少量性能開銷 -3. **網路依賴**:需要確保主機和備機之間的網路連接穩定 -4. **權限配置**:確保備機資料庫有足夠的權限進行操作 - -## 故障排除 - -### 常見問題 - -1. **備機連接失敗** - - 檢查網路連接 - - 驗證資料庫配置 - - 確認用戶權限 - -2. **同步失敗** - - 檢查表結構是否一致 - - 確認資料庫權限 - - 查看錯誤日誌 - -3. **自動切換不工作** - - 確認 `DB_FAILOVER_ENABLED=true` - - 檢查健康檢查間隔設定 - - 查看系統日誌 - -### 日誌位置 - -- 應用程式日誌:控制台輸出 -- 資料庫日誌:MySQL 錯誤日誌 -- 系統日誌:系統日誌文件 - -## 最佳實踐 - -1. **定期備份**:即使有備援機制,仍建議定期備份資料 -2. **監控告警**:設定監控告警,及時發現問題 -3. **測試切換**:定期測試備援切換功能 -4. **性能監控**:監控資料庫性能指標 -5. **文檔更新**:保持配置文檔的更新 - -## 技術架構 - -``` -┌─────────────────┐ ┌─────────────────┐ -│ 應用程式 │ │ 應用程式 │ -└─────────┬───────┘ └─────────┬───────┘ - │ │ - ▼ ▼ -┌─────────────────┐ ┌─────────────────┐ -│ 資料庫服務 │ │ 備援服務 │ -│ (主機) │ │ (備機) │ -└─────────────────┘ └─────────────────┘ - │ │ - ▼ ▼ -┌─────────────────┐ ┌─────────────────┐ -│ MySQL 主機 │ │ MySQL 備機 │ -│ mysql.theaken │ │ 122.100.99.161│ -│ .com:33306 │ │ :43306 │ -└─────────────────┘ └─────────────────┘ -``` - -## 支援 - -如有問題,請檢查: - -1. 環境變數配置 -2. 網路連接狀態 -3. 資料庫服務狀態 -4. 系統日誌 -5. 監控面板狀態 diff --git a/README-DATABASE.md b/README-DATABASE.md deleted file mode 100644 index 9d0adc4..0000000 --- a/README-DATABASE.md +++ /dev/null @@ -1,222 +0,0 @@ -# AI 展示平台資料庫設計 - -## 📊 資料庫概述 - -本專案使用 **MySQL** 作為主要資料庫,設計了完整的資料表結構來支持 AI 展示平台的所有功能。 - -### 🔗 資料庫連接資訊 - -- **主機**: `mysql.theaken.com` -- **端口**: `33306` -- **資料庫名**: `db_AI_Platform` -- **用戶名**: `AI_Platform` -- **密碼**: `Aa123456` - -## 🏗️ 資料表結構 - -### 核心業務表 - -#### 1. 用戶管理 -- **users** - 用戶基本資訊 -- **user_favorites** - 用戶收藏應用 -- **user_likes** - 用戶按讚記錄 -- **user_views** - 用戶瀏覽記錄 -- **user_ratings** - 用戶評分記錄 - -#### 2. 競賽系統 -- **competitions** - 競賽基本資訊 -- **competition_rules** - 競賽規則 -- **competition_award_types** - 競賽獎項類型 -- **competition_judges** - 競賽評審關聯 -- **competition_apps** - 競賽參與應用 -- **competition_teams** - 競賽參與團隊 -- **competition_proposals** - 競賽參與提案 - -#### 3. 評審系統 -- **judges** - 評審基本資訊 -- **app_judge_scores** - 應用評分記錄 -- **proposal_judge_scores** - 提案評分記錄 - -#### 4. 團隊管理 -- **teams** - 團隊基本資訊 -- **team_members** - 團隊成員關聯 - -#### 5. 應用管理 -- **apps** - AI 應用基本資訊 - -#### 6. 提案管理 -- **proposals** - 提案基本資訊 - -#### 7. 獎項系統 -- **awards** - 獎項記錄 - -#### 8. AI 助手 -- **chat_sessions** - 聊天會話 -- **chat_messages** - 聊天訊息 -- **ai_assistant_configs** - AI 助手配置 - -#### 9. 系統管理 -- **system_settings** - 系統設定 -- **activity_logs** - 活動日誌 - -## 📈 統計視圖 - -### 1. user_statistics -用戶統計視圖,包含: -- 基本資訊 -- 收藏數量 -- 按讚數量 -- 瀏覽數量 -- 平均評分 -- 團隊參與情況 - -### 2. app_statistics -應用統計視圖,包含: -- 基本資訊 -- 創作者資訊 -- 團隊資訊 -- 用戶互動統計 -- 評審評分統計 - -### 3. competition_statistics -競賽統計視圖,包含: -- 基本資訊 -- 評審數量 -- 參與應用數量 -- 參與團隊數量 -- 參與提案數量 -- 獎項數量 - -## ⚙️ 觸發器 - -### 1. 自動計算總分 -- **calculate_app_total_score** - 應用評分總分計算 -- **calculate_proposal_total_score** - 提案評分總分計算 - -## 🚀 快速開始 - -### 1. 安裝依賴 - -```bash -npm install -``` - -### 2. 設置環境變數 - -複製 `env.example` 到 `.env.local` 並填入正確的資料庫資訊: - -```bash -cp env.example .env.local -``` - -### 3. 執行資料庫遷移 - -```bash -# 創建資料庫結構 -npm run migrate - -# 重置資料庫(慎用) -npm run migrate:reset -``` - -### 4. 驗證安裝 - -遷移完成後,您應該看到: -- 25 個資料表 -- 3 個統計視圖 -- 4 個觸發器 -- 初始系統設定數據 - -## 🔧 資料庫服務 - -### 使用方式 - -```typescript -import { UserService, CompetitionService, AppService } from '@/lib/services/database-service'; - -// 創建用戶 -const user = await UserService.createUser({ - name: '張三', - email: 'zhang@example.com', - password_hash: 'hashed_password', - department: 'IT部門', - role: 'developer', - join_date: '2024-01-01', - total_likes: 0, - total_views: 0, - is_active: true -}); - -// 獲取用戶統計 -const stats = await UserService.getUserStatistics(user.id); - -// 創建競賽 -const competition = await CompetitionService.createCompetition({ - name: '2024年AI創新競賽', - year: 2024, - month: 3, - start_date: '2024-03-01', - end_date: '2024-03-31', - status: 'upcoming', - type: 'individual', - is_active: true -}); -``` - -## 📋 資料表關係圖 - -``` -users (1) ←→ (N) team_members (N) ←→ (1) teams -users (1) ←→ (N) apps -users (1) ←→ (N) user_favorites -users (1) ←→ (N) user_likes -users (1) ←→ (N) user_views -users (1) ←→ (N) user_ratings - -competitions (1) ←→ (N) competition_judges (N) ←→ (1) judges -competitions (1) ←→ (N) competition_apps (N) ←→ (1) apps -competitions (1) ←→ (N) competition_teams (N) ←→ (1) teams -competitions (1) ←→ (N) competition_proposals (N) ←→ (1) proposals -competitions (1) ←→ (N) awards - -judges (1) ←→ (N) app_judge_scores (N) ←→ (1) apps -judges (1) ←→ (N) proposal_judge_scores (N) ←→ (1) proposals - -teams (1) ←→ (N) proposals -teams (1) ←→ (N) apps -``` - -## 🛠️ 維護命令 - -### 備份資料庫 -```bash -mysqldump -h mysql.theaken.com -P 33306 -u AI_Platform -p db_AI_Platform > backup.sql -``` - -### 恢復資料庫 -```bash -mysql -h mysql.theaken.com -P 33306 -u AI_Platform -p db_AI_Platform < backup.sql -``` - -### 檢查資料庫狀態 -```bash -mysql -h mysql.theaken.com -P 33306 -u AI_Platform -p -e "SHOW TABLES;" db_AI_Platform -``` - -## 🔍 常見問題 - -### Q: 如何重置資料庫? -A: 執行 `npm run migrate:reset` 命令,這會刪除所有表並重新創建。 - -### Q: 如何添加新的資料表? -A: 在 `database-schema.sql` 中添加新的 CREATE TABLE 語句,然後執行 `npm run migrate`。 - -### Q: 如何修改現有表結構? -A: 使用 ALTER TABLE 語句,或者創建新的遷移腳本。 - -### Q: 資料庫連接失敗怎麼辦? -A: 檢查環境變數設置,確保資料庫服務正在運行,並且網路連接正常。 - -## 📞 技術支援 - -如有任何資料庫相關問題,請聯繫技術團隊或查看專案文檔。 diff --git a/README-DUAL-WRITE-SYNC.md b/README-DUAL-WRITE-SYNC.md deleted file mode 100644 index d3b4a4d..0000000 --- a/README-DUAL-WRITE-SYNC.md +++ /dev/null @@ -1,237 +0,0 @@ -# 資料庫雙寫同步系統說明 - -## 🎯 系統概述 - -本系統實現了主機和備機資料庫的雙寫同步機制,確保所有新增、刪除、修改的資料都能同時寫入主機和備機資料庫,實現真正的資料同步。 - -## ✅ 主要功能 - -- ✅ **雙寫同步** - 所有寫入操作同時寫入主機和備機 -- ✅ **自動故障檢測** - 每30秒檢查資料庫健康狀態 -- ✅ **自動切換** - 主機故障時自動切換到備機 -- ✅ **手動切換** - 支援手動切換資料庫 -- ✅ **資料同步** - 可將主機資料同步到備機 -- ✅ **監控面板** - 實時監控資料庫狀態 -- ✅ **健康檢查** - 定期檢查連接狀態 - -## 🚀 快速開始 - -### 1. 環境變數配置 - -在您的 `.env` 文件中添加以下配置: - -```env -# ===== 主機資料庫配置 ===== -DB_HOST=mysql.theaken.com -DB_PORT=33306 -DB_NAME=db_AI_Platform -DB_USER=AI_Platform -DB_PASSWORD=Aa123456 - -# ===== 備機資料庫配置 ===== -SLAVE_DB_HOST=122.100.99.161 -SLAVE_DB_PORT=43306 -SLAVE_DB_NAME=db_AI_Platform -SLAVE_DB_USER=A999 -SLAVE_DB_PASSWORD=1023 - -# ===== 資料庫備援配置 ===== -DB_FAILOVER_ENABLED=true - -# ===== 資料庫雙寫同步配置 ===== -DB_DUAL_WRITE_ENABLED=true -DB_MASTER_PRIORITY=true -DB_CONFLICT_RESOLUTION=master -DB_HEALTH_CHECK_INTERVAL=30000 -DB_CONNECTION_TIMEOUT=5000 -DB_RETRY_ATTEMPTS=3 -DB_RETRY_DELAY=2000 -``` - -### 2. 初始化備機資料庫 - -```bash -# 初始化備機資料庫結構 -pnpm run db:init-slave - -# 同步主機資料到備機 -pnpm run db:sync -``` - -### 3. 測試雙寫功能 - -```bash -# 測試雙寫同步功能 -pnpm run db:test-dual-write - -# 檢查資料庫健康狀態 -pnpm run db:health -``` - -## 📊 工作原理 - -### 雙寫流程 - -1. **寫入請求** - API 接收到寫入請求 -2. **雙寫執行** - 同時寫入主機和備機資料庫 -3. **結果處理** - 根據寫入結果決定回應 -4. **錯誤處理** - 如果其中一個失敗,記錄錯誤但繼續服務 - -### 同步策略 - -- **主機優先** - 如果主機和備機都成功,優先返回主機結果 -- **備機備援** - 如果主機失敗但備機成功,使用備機結果 -- **錯誤處理** - 如果兩者都失敗,拋出錯誤 - -## 🔧 程式碼使用 - -### 基本使用 - -系統會自動使用雙寫功能,無需修改現有程式碼: - -```typescript -import { db } from '@/lib/database'; - -// 插入資料 (自動雙寫) -await db.insert('INSERT INTO users (name, email) VALUES (?, ?)', ['John', 'john@example.com']); - -// 更新資料 (自動雙寫) -await db.update('UPDATE users SET name = ? WHERE id = ?', ['Jane', 'user-id']); - -// 刪除資料 (自動雙寫) -await db.delete('DELETE FROM users WHERE id = ?', ['user-id']); - -// 查詢資料 (自動使用備援) -const users = await db.query('SELECT * FROM users'); -``` - -### 監控同步狀態 - -```typescript -import { dbSync } from '@/lib/database-sync'; - -// 獲取同步狀態 -const status = await dbSync.getSyncStatus(); -console.log('同步狀態:', status); - -// 手動同步表 -await dbSync.syncFromMasterToSlave('users'); -``` - -### 獲取備援狀態 - -```typescript -import { db } from '@/lib/database'; - -// 獲取當前資料庫狀態 -const status = db.getFailoverStatus(); -console.log('當前使用資料庫:', status?.currentDatabase); -console.log('主機健康狀態:', status?.masterHealthy); -console.log('備機健康狀態:', status?.slaveHealthy); -``` - -## 📈 監控和管理 - -### 可用命令 - -| 命令 | 功能 | 狀態 | -|------|------|------| -| `pnpm run db:health` | 檢查資料庫健康狀態 | ✅ 可用 | -| `pnpm run db:test-dual-write` | 測試雙寫同步功能 | ✅ 可用 | -| `pnpm run db:init-slave` | 初始化備機資料庫 | ✅ 可用 | -| `pnpm run db:sync` | 同步資料 | ✅ 可用 | -| `pnpm run db:monitor` | 監控資料庫狀態 | ✅ 可用 | - -### 管理頁面 - -在管理頁面中添加監控組件: - -```typescript -import { DatabaseMonitor } from '@/components/admin/database-monitor'; - -// 在管理頁面中使用 - -``` - -## 🚨 故障處理 - -### 主機資料庫問題 - -**問題**: `Too many connections` -**解決方案**: -1. 系統已自動切換到備機 -2. 檢查主機資料庫連接數限制 -3. 優化連接池配置 -4. 重啟主機資料庫服務 - -### 備機資料庫問題 - -**問題**: 備機連接失敗 -**解決方案**: -1. 檢查網路連接 -2. 驗證備機資料庫配置 -3. 確認用戶權限 -4. 檢查備機資料庫服務狀態 - -### 雙寫失敗處理 - -**問題**: 主機或備機寫入失敗 -**解決方案**: -1. 檢查錯誤日誌 -2. 驗證資料庫連接狀態 -3. 檢查資料庫結構一致性 -4. 重新執行失敗的操作 - -## 📋 維護建議 - -### 定期維護 - -1. **每日檢查**: 執行 `pnpm run db:health` -2. **每週測試**: 執行 `pnpm run db:test-dual-write` -3. **每月同步**: 執行 `pnpm run db:sync` - -### 監控指標 - -- 資料庫連接狀態 -- 雙寫成功率 -- 同步延遲時間 -- 錯誤率統計 - -## 🔄 恢復主機 - -當主機資料庫恢復後: - -1. 檢查主機狀態: `pnpm run db:health` -2. 手動切換回主機: `await db.switchDatabase('master')` -3. 重新同步資料: `pnpm run db:sync` - -## 📞 支援 - -如有問題,請檢查: - -1. 環境變數配置 -2. 網路連接狀態 -3. 資料庫服務狀態 -4. 系統日誌 -5. 監控面板狀態 - -## 🎉 總結 - -您的資料庫雙寫同步系統已經成功設置並運行!系統現在可以: - -- ✅ 自動檢測主機資料庫問題 -- ✅ 自動切換到備機資料庫 -- ✅ 實現真正的雙寫同步 -- ✅ 確保資料一致性 -- ✅ 提供監控和管理功能 -- ✅ 確保服務連續性 - -即使主機資料庫出現問題,您的應用程式仍然可以正常運行,並且所有資料都會同步到備機! - - - - - - - - diff --git a/README-ENV.md b/README-ENV.md deleted file mode 100644 index 2f427c2..0000000 --- a/README-ENV.md +++ /dev/null @@ -1,56 +0,0 @@ -# 環境變數設定說明 - -## DeepSeek API 設定 - -本專案使用 DeepSeek API 作為聊天機器人的 AI 服務。請按照以下步驟設定環境變數: - -### 1. 創建環境變數檔案 - -在專案根目錄創建 `.env.local` 檔案: - -```bash -# DeepSeek API Configuration -NEXT_PUBLIC_DEEPSEEK_API_KEY=your_deepseek_api_key_here -NEXT_PUBLIC_DEEPSEEK_API_URL=https://api.deepseek.com/v1/chat/completions -``` - -### 2. 取得 DeepSeek API 金鑰 - -1. 前往 [DeepSeek 官網](https://platform.deepseek.com/) -2. 註冊或登入帳號 -3. 在控制台中生成 API 金鑰 -4. 將金鑰複製到 `.env.local` 檔案中的 `NEXT_PUBLIC_DEEPSEEK_API_KEY` - -### 3. 環境變數說明 - -- `NEXT_PUBLIC_DEEPSEEK_API_KEY`: DeepSeek API 金鑰 -- `NEXT_PUBLIC_DEEPSEEK_API_URL`: DeepSeek API 端點 URL - -### 4. 安全注意事項 - -- `.env.local` 檔案已加入 `.gitignore`,不會被提交到版本控制 -- 請勿將 API 金鑰分享給他人 -- 在生產環境中,請使用更安全的環境變數管理方式 - -### 5. 重新啟動開發伺服器 - -設定完成後,請重新啟動開發伺服器: - -```bash -npm run dev -# 或 -pnpm dev -``` - -### 6. 驗證設定 - -聊天機器人應該能夠正常運作,並能夠回答用戶問題。 - -## 故障排除 - -如果聊天機器人無法運作: - -1. 確認 `.env.local` 檔案存在且格式正確 -2. 確認 API 金鑰有效且未過期 -3. 檢查網路連接是否正常 -4. 查看瀏覽器開發者工具中的錯誤訊息 \ No newline at end of file diff --git a/README-SCORING-BACKEND.md b/README-SCORING-BACKEND.md deleted file mode 100644 index fc63272..0000000 --- a/README-SCORING-BACKEND.md +++ /dev/null @@ -1,195 +0,0 @@ -# 評分機制後端實現文檔 - -## 概述 - -本文檔描述了AI展示平台評分機制的後端實現,包括資料庫設計、API端點和前端整合。 - -## 資料庫設計 - -### 評分相關表格 - -1. **app_judge_scores** - 應用評分表 - - 存儲評審對應用的評分記錄 - - 包含創新性、技術性、實用性、展示效果、影響力等評分項目 - - 自動計算總分 - -2. **proposal_judge_scores** - 提案評分表 - - 存儲評審對提案的評分記錄 - - 包含問題識別、解決方案可行性、創新性、影響力、展示效果等評分項目 - - 自動計算總分 - -3. **competition_judges** - 競賽評審關聯表 - - 管理競賽與評審的關聯關係 - -4. **competition_apps** - 競賽應用關聯表 - - 管理競賽與應用的關聯關係 - -5. **competition_proposals** - 競賽提案關聯表 - - 管理競賽與提案的關聯關係 - -## API端點 - -### 1. 評分管理 API (`/api/admin/scoring`) - -#### GET - 獲取評分記錄 -``` -GET /api/admin/scoring?competitionId={id}&judgeId={id}&status={status}&search={query} -``` - -**參數:** -- `competitionId` (必需): 競賽ID -- `judgeId` (可選): 評審ID,用於篩選特定評審的評分 -- `status` (可選): 狀態篩選 (all/completed/pending) -- `search` (可選): 搜尋關鍵字 - -**回應:** -```json -{ - "success": true, - "message": "評分記錄獲取成功", - "data": { - "scores": [...], - "stats": {...}, - "total": 10 - } -} -``` - -#### POST - 提交評分 -``` -POST /api/admin/scoring -``` - -**請求體:** -```json -{ - "judgeId": "judge_id", - "participantId": "app_id", - "participantType": "app", - "scores": { - "innovation_score": 8, - "technical_score": 7, - "usability_score": 9, - "presentation_score": 8, - "impact_score": 7 - }, - "comments": "評審意見" -} -``` - -### 2. 評分記錄管理 API (`/api/admin/scoring/[id]`) - -#### PUT - 更新評分記錄 -``` -PUT /api/admin/scoring/{id} -``` - -#### DELETE - 刪除評分記錄 -``` -DELETE /api/admin/scoring/{id}?type={app|proposal} -``` - -### 3. 評分統計 API (`/api/admin/scoring/stats`) - -#### GET - 獲取評分統計 -``` -GET /api/admin/scoring/stats?competitionId={id} -``` - -**回應:** -```json -{ - "success": true, - "message": "評分統計獲取成功", - "data": { - "totalScores": 20, - "completedScores": 15, - "pendingScores": 5, - "completionRate": 75, - "totalParticipants": 10 - } -} -``` - -## 後端服務 - -### ScoringService 類別 - -提供以下主要方法: - -1. **submitAppScore()** - 提交應用評分 -2. **submitProposalScore()** - 提交提案評分 -3. **getCompetitionScores()** - 獲取競賽所有評分記錄 -4. **getCompetitionScoreStats()** - 獲取競賽評分統計 -5. **getJudgeScores()** - 獲取評審的評分記錄 -6. **updateAppScore()** - 更新應用評分 -7. **updateProposalScore()** - 更新提案評分 -8. **deleteScore()** - 刪除評分記錄 - -## 前端整合 - -### 組件更新 - -1. **ScoringManagement 組件** - - 更新 `loadScoringData()` 方法以使用API - - 更新 `handleSubmitScore()` 方法以提交到後端 - - 添加評分統計功能 - -2. **CompetitionContext 上下文** - - 更新 `submitJudgeScore()` 方法以使用API - - 保持向後兼容性 - -### 數據流程 - -1. 用戶選擇競賽 -2. 前端調用 `/api/admin/scoring/stats` 獲取統計數據 -3. 前端調用 `/api/admin/scoring` 獲取評分記錄 -4. 用戶提交評分時調用 POST `/api/admin/scoring` -5. 後端更新資料庫並返回結果 -6. 前端重新載入數據以顯示最新狀態 - -## 評分規則 - -### 應用評分項目 -- 創新性 (innovation_score): 1-10分 -- 技術性 (technical_score): 1-10分 -- 實用性 (usability_score): 1-10分 -- 展示效果 (presentation_score): 1-10分 -- 影響力 (impact_score): 1-10分 - -### 提案評分項目 -- 問題識別 (problem_identification_score): 1-10分 -- 解決方案可行性 (solution_feasibility_score): 1-10分 -- 創新性 (innovation_score): 1-10分 -- 影響力 (impact_score): 1-10分 -- 展示效果 (presentation_score): 1-10分 - -### 總分計算 -總分 = (所有評分項目之和) / 評分項目數量 - -## 測試 - -### 資料庫測試 -```bash -node scripts/test-scoring.js -``` - -### API測試 -```bash -node scripts/test-scoring-api.js -``` - -## 部署注意事項 - -1. 確保資料庫表格已創建 -2. 確保觸發器正常工作(自動計算總分) -3. 檢查API端點權限設置 -4. 驗證前端組件與API的整合 - -## 未來改進 - -1. 添加評分權重配置 -2. 實現評分審核流程 -3. 添加評分歷史記錄 -4. 實現批量評分功能 -5. 添加評分導出功能 diff --git a/README-SCORING.md b/README-SCORING.md deleted file mode 100644 index 4c25e4e..0000000 --- a/README-SCORING.md +++ /dev/null @@ -1,123 +0,0 @@ -# 評分管理功能 - -## 功能概述 - -後台評分管理系統提供了完整的評分管理功能,包括: - -- 查看已完成和未完成的評分內容 -- 手動輸入和編輯評分 -- 評分進度追蹤 -- 篩選和搜尋功能 - -## 主要功能 - -### 1. 競賽選擇 -- 從下拉選單中選擇要管理的競賽 -- 顯示競賽基本資訊(名稱、類型、時間等) - -### 2. 評分概覽 -- **已完成評分**:顯示已完成的評分數量 -- **待評分**:顯示待評分的數量 -- **完成度**:顯示評分進度的百分比 -- **總評分項目**:顯示總評分項目數量 -- 進度條:視覺化顯示評分進度 - -### 3. 評分記錄管理 -- **評審**:顯示評審姓名和頭像 -- **參賽者**:顯示參賽者名稱和類型(個人/團隊) -- **類型**:標示參賽者類型 -- **總分**:顯示評分總分 -- **狀態**:顯示評分狀態(已完成/待評分) -- **提交時間**:顯示評分提交時間 -- **操作**:編輯或新增評分 - -### 4. 篩選和搜尋 -- **狀態篩選**:按評分狀態篩選(全部/已完成/待評分) -- **搜尋功能**:搜尋評審或參賽者名稱 -- **分頁功能**:支援大量數據的分頁顯示 - -### 5. 動態評分功能 -- **評審選擇**:從評審列表中選擇評審 -- **參賽者選擇**:從參賽者列表中選擇參賽者 -- **動態評分項目**:根據競賽建立時設定的評比規則動態生成評分項目 -- **權重計算**:支援不同評分項目的權重設定 -- **評分驗證**:確保所有評分項目都已評分 -- **總分計算**:根據權重自動計算總分 -- **評審意見**:填寫評審意見和建議 -- **評分提交**:提交或更新評分 - -## 使用方式 - -### 訪問評分管理 -1. 進入後台管理系統 -2. 點擊「評分管理」標籤 -3. 選擇要管理的競賽 - -### 查看評分記錄 -1. 選擇競賽後,系統會自動載入該競賽的所有評分記錄 -2. 使用篩選功能查看特定狀態的評分 -3. 使用搜尋功能快速找到特定評審或參賽者的評分 - -### 動態評分輸入 -1. 點擊「手動輸入評分」按鈕 -2. 選擇評審和參賽者 -3. 根據競賽設定的評比項目進行評分 -4. 為每個評分項目選擇分數(1-10分) -5. 系統會根據權重自動計算總分 -6. 填寫評審意見 -7. 點擊「提交評分」完成評分 - -### 編輯現有評分 -1. 在評分記錄表格中點擊編輯按鈕 -2. 修改評審意見 -3. 點擊「更新評分」保存修改 - -## 技術實現 - -### 組件結構 -- `ScoringManagement`:主要評分管理組件 -- 整合到現有的 `CompetitionManagement` 組件中 - -### 動態評分系統 -- **評比規則讀取**:從競賽的 `rules` 屬性讀取評比項目 -- **動態評分項目生成**:根據競賽規則動態生成評分表單 -- **權重計算**:支援不同評分項目的權重設定 -- **評分驗證**:確保所有評分項目都已評分 -- **總分計算**:根據權重自動計算總分 - -### 數據流 -1. 從 `useCompetition` 上下文獲取競賽和評分數據 -2. 根據選擇的競賽載入相關的評審和參賽者 -3. 讀取競賽的評比規則並動態生成評分項目 -4. 生成評分記錄列表 -5. 支援篩選、搜尋和分頁功能 - -### 狀態管理 -- 使用 React hooks 管理組件狀態 -- 整合現有的競賽上下文 -- 支援即時數據更新 -- 動態評分項目的狀態管理 - -## 文件結構 - -``` -components/admin/ -├── scoring-management.tsx # 評分管理組件 -└── competition-management.tsx # 競賽管理組件(已整合) - -app/admin/ -└── scoring/ - └── page.tsx # 評分管理頁面 -``` - -## 注意事項 - -1. 評分記錄會根據競賽的評審和參賽者自動生成 -2. 已完成的評分可以編輯,未完成的評分可以新增 -3. 評分提交後會即時更新列表 -4. 支援個人賽和團隊賽的評分管理 -5. 評分數據與現有的競賽管理系統完全整合 -6. 評分項目會根據競賽建立時設定的評比規則動態生成 -7. 如果競賽沒有設定評比規則,會使用預設的評分項目 -8. 總分會根據各評分項目的權重自動計算 -9. 系統會驗證所有評分項目都已評分才能提交 \ No newline at end of file diff --git a/SCORING-FORM-COMPLETE-FIX.md b/SCORING-FORM-COMPLETE-FIX.md deleted file mode 100644 index 9ed239d..0000000 --- a/SCORING-FORM-COMPLETE-FIX.md +++ /dev/null @@ -1,133 +0,0 @@ -# 評分表單完全修復報告 - -## 問題診斷結果 - -根據用戶提供的Console日誌分析: - -``` -🏆 當前競賽API回應: {success: true, message: '當前競賽獲取成功', data: {…}} -✅ 當前競賽載入成功: AA -👨‍⚖️ 評審列表渲染 - judges (context): [] ← 問題所在 -``` - -**根本原因**:`useCompetition` hook 中的 `judges` 數據沒有被載入,導致評審選項為空。 - -## 完整修復方案 - -### 1. 修復評審數據載入 (`contexts/competition-context.tsx`) - -```typescript -// 載入評審數據 -console.log('👨‍⚖️ 開始載入評審數據...') -const judgesResponse = await fetch('/api/admin/judges') -const judgesData = await judgesResponse.json() -console.log('評審API回應:', judgesData) - -if (judgesData.success && judgesData.data) { - setJudges(judgesData.data) - console.log('✅ 評審數據載入成功:', judgesData.data.length, '個評審') -} else { - console.error('❌ 評審數據載入失敗:', judgesData.message) - setJudges([]) -} -``` - -### 2. 修復競賽數據載入 (`components/admin/scoring-management.tsx`) - -```typescript -useEffect(() => { - if (selectedCompetition) { - loadScoringData() - loadCompetitionData() // 添加這行 - } -}, [selectedCompetition]) -``` - -### 3. 添加自動競賽選擇 - -```typescript -// 自動選擇第一個競賽(如果沒有選中的話) -if (!selectedCompetition) { - console.log('🎯 自動選擇第一個競賽:', competitions[0].name) - setSelectedCompetition(competitions[0]) -} -``` - -## 測試結果 - -### API測試結果 ✅ -``` -📋 競賽API成功: 1 個競賽 -👨‍⚖️ 評審API成功: 1 個評審 -🏆 競賽評審API成功: 1 個評審 -👥 競賽團隊API成功: 1 個團隊 -📱 競賽應用API成功: 0 個應用 -``` - -### 數據可用性 ✅ -- **競賽**: AA (team) -- **評審**: 1 個 (aa - ITBU) -- **團隊**: 1 個 (aaa - 隊長: Wu Petty) -- **應用**: 0 個 (正常,因為這是團隊競賽) - -## 預期Console日誌 - -修復後,用戶應該在Console中看到: - -``` -🔄 開始載入競賽數據... -📋 競賽API回應: {success: true, data: [...]} -✅ 競賽數據載入成功: 1 個競賽 -🏆 當前競賽API回應: {success: true, data: {...}} -✅ 當前競賽載入成功: AA -👨‍⚖️ 開始載入評審數據... -評審API回應: {success: true, data: [...]} -✅ 評審數據載入成功: 1 個評審 -✅ 競賽數據已載入,關閉初始載入狀態 -🎯 自動選擇第一個競賽: AA -🔍 開始載入競賽數據,競賽ID: be47d842-91f1-11f0-8595-bd825523ae01 -📋 載入競賽評審... -✅ 評審數據載入成功: 1 個評審 -📱 載入競賽參賽者... -✅ 團隊數據載入成功: 1 個團隊 -✅ 參賽者數據載入完成: 1 個參賽者 -``` - -## 功能驗證 - -### 1. 評審選擇 ✅ -- 下拉選單應該顯示 "aa (aa) - ITBU" -- 可以正常選擇評審 - -### 2. 參賽者選擇 ✅ -- 下拉選單應該顯示 "aaa (團隊) - Wu Petty" -- 可以正常選擇參賽者 - -### 3. 評分提交 ✅ -- 選擇評審和參賽者後可以填寫評分 -- 評分數據會正確提交到後端 - -## 技術特點 - -- **完整的數據載入鏈**:競賽 → 評審 → 參賽者 -- **自動競賽選擇**:無需手動選擇競賽 -- **詳細的調試日誌**:便於問題排查 -- **錯誤恢復機制**:防止因API失敗導致的界面崩潰 -- **用戶友好體驗**:加載狀態指示和自動選擇 - -## 使用方式 - -1. **刷新頁面**:讓修復生效 -2. **查看Console**:確認看到完整的載入日誌 -3. **測試功能**:選擇評審和參賽者進行評分 -4. **調試頁面**:訪問 `http://localhost:3000/debug-scoring` 查看詳細信息 - -## 修復完成 ✅ - -現在評分表單應該完全正常工作: -- ✅ 評審選項可以選擇 -- ✅ 參賽者選項可以選擇 -- ✅ Console顯示詳細的調試信息 -- ✅ 評分功能完全可用 - -所有問題已解決! diff --git a/SCORING-FORM-DEBUG.md b/SCORING-FORM-DEBUG.md deleted file mode 100644 index 55ab8a2..0000000 --- a/SCORING-FORM-DEBUG.md +++ /dev/null @@ -1,147 +0,0 @@ -# 評分表單調試修復報告 - -## 問題分析 - -用戶反映手動評審評分表單無法選擇評審和團隊,經過分析發現以下問題: - -### 1. 數據載入問題 -- 前端組件嘗試從API載入數據,但API回應格式可能不正確 -- 缺少適當的錯誤處理和加載狀態指示 - -### 2. 數據格式不匹配 -- API回應的數據結構與前端期望的格式不一致 -- 缺少對空數據的處理 - -## 修復內容 - -### 1. 增強錯誤處理 (`components/admin/scoring-management.tsx`) - -#### 添加調試日誌 -```typescript -console.log('🔍 開始載入競賽數據,競賽ID:', selectedCompetition.id) -console.log('評審API回應:', judgesData) -console.log('應用API回應:', appsData) -console.log('團隊API回應:', teamsData) -``` - -#### 改善數據驗證 -```typescript -if (judgesData.success && judgesData.data && judgesData.data.judges) { - setCompetitionJudges(judgesData.data.judges) -} else { - console.error('❌ 評審數據載入失敗:', judgesData.message || 'API回應格式錯誤') - setCompetitionJudges([]) -} -``` - -### 2. 添加加載狀態指示 - -#### 新增狀態管理 -```typescript -const [isLoadingData, setIsLoadingData] = useState(false) -``` - -#### 加載狀態UI -```typescript -{isLoadingData ? ( - -
- - 載入評審中... -
-
-) : competitionJudges.length > 0 ? ( - // 顯示評審選項 -) : ( - - 暫無評審數據 - -)} -``` - -### 3. 改善數據映射 - -#### 修正API數據結構 -```typescript -// 評審數據 -if (judgesData.success && judgesData.data && judgesData.data.judges) { - setCompetitionJudges(judgesData.data.judges) -} - -// 應用數據 -if (appsData.success && appsData.data && appsData.data.apps) { - participants.push(...appsData.data.apps.map((app: any) => ({ - id: app.id, - name: app.name, - type: 'individual', - creator: app.creator - }))) -} - -// 團隊數據 -if (teamsData.success && teamsData.data && teamsData.data.teams) { - participants.push(...teamsData.data.teams.map((team: any) => ({ - id: team.id, - name: team.name, - type: 'team', - creator: team.members && team.members.find((m: any) => m.role === '隊長')?.name || '未知隊長' - }))) -} -``` - -### 4. 創建測試工具 - -#### 資料庫測試腳本 (`scripts/test-data-loading.js`) -- 直接測試資料庫連接 -- 驗證競賽、評審、應用、團隊數據 -- 檢查數據關聯性 - -#### API測試頁面 (`app/test-api/page.tsx`) -- 提供Web界面測試API端點 -- 實時查看API回應 -- 方便調試數據格式問題 - -## 測試結果 - -### 資料庫測試結果 -``` -🏆 競賽: AA (ID: be47d842-91f1-11f0-8595-bd825523ae01) -👨‍⚖️ 評審: 1 個 (aa - ITBU) -📱 應用: 0 個 -👥 團隊: 1 個 (aaa - 隊長: Wu Petty) -📊 評分記錄: 0 個 -``` - -### 發現的問題 -1. **競賽有評審和團隊數據** ✅ -2. **沒有應用數據** ⚠️ (這可能是正常的,如果競賽只允許團隊參賽) -3. **API端點存在且正常** ✅ - -## 使用方式 - -### 1. 測試API端點 -訪問 `http://localhost:3000/test-api` 來測試API回應 - -### 2. 查看調試日誌 -打開瀏覽器開發者工具的Console,查看詳細的載入日誌 - -### 3. 檢查數據載入 -- 選擇競賽後,查看Console中的載入日誌 -- 確認API回應格式正確 -- 檢查是否有錯誤訊息 - -## 下一步建議 - -1. **檢查競賽設置**:確認競賽是否正確配置了評審和參賽者 -2. **驗證API回應**:使用測試頁面檢查API是否返回正確數據 -3. **檢查網路請求**:在瀏覽器Network標籤中查看API請求狀態 -4. **添加更多調試信息**:如果問題持續,可以添加更詳細的日誌 - -## 技術特點 - -- **完整的錯誤處理**:防止因API失敗導致的界面崩潰 -- **用戶友好的加載狀態**:清楚顯示數據載入進度 -- **詳細的調試信息**:便於問題排查和修復 -- **測試工具**:提供多種方式驗證系統狀態 - -修復完成後,評分表單應該能夠正確載入和顯示評審及參賽者選項。 diff --git a/SCORING-FORM-FINAL-FIX.md b/SCORING-FORM-FINAL-FIX.md deleted file mode 100644 index fa3c173..0000000 --- a/SCORING-FORM-FINAL-FIX.md +++ /dev/null @@ -1,177 +0,0 @@ -# 評分表單最終修復報告 - -## 問題診斷 - -用戶反映評分表單無法選擇評審和團隊,Console也沒有資訊輸出。經過深入診斷發現: - -### 根本原因 -1. **API端點正常** ✅ - 所有API端點都正常工作 -2. **資料庫連接正常** ✅ - 資料庫連接和查詢都正常 -3. **前端數據載入問題** ❌ - 前端組件沒有正確等待數據載入完成 - -### 具體問題 -- `useCompetition` hook 中的數據載入是異步的 -- `ScoringManagement` 組件在數據載入完成前就嘗試渲染 -- 缺少適當的加載狀態指示 -- 調試日誌沒有正確輸出 - -## 修復內容 - -### 1. 增強調試日誌 (`contexts/competition-context.tsx`) - -```typescript -// 載入所有競賽和當前競賽 -useEffect(() => { - const loadCompetitions = async () => { - try { - console.log('🔄 開始載入競賽數據...') - - // 載入所有競賽 - const competitionsResponse = await fetch('/api/competitions') - const competitionsData = await competitionsResponse.json() - console.log('📋 競賽API回應:', competitionsData) - - if (competitionsData.success && competitionsData.data) { - setCompetitions(competitionsData.data) - console.log('✅ 競賽數據載入成功:', competitionsData.data.length, '個競賽') - } else { - console.error('❌ 競賽數據載入失敗:', competitionsData.message) - setCompetitions([]) - } - } catch (error) { - console.error('❌ 載入競賽數據失敗:', error) - } - } - - loadCompetitions() -}, []) -``` - -### 2. 添加加載狀態管理 (`components/admin/scoring-management.tsx`) - -```typescript -// 新增狀態 -const [isInitialLoading, setIsInitialLoading] = useState(true) - -// 檢查初始載入狀態 -useEffect(() => { - if (competitions && competitions.length > 0) { - console.log('✅ 競賽數據已載入,關閉初始載入狀態') - setIsInitialLoading(false) - } -}, [competitions]) -``` - -### 3. 添加加載指示器 - -```typescript -// 顯示初始載入狀態 -if (isInitialLoading) { - return ( -
- - -
- -

載入競賽數據中...

-

請稍候,正在從服務器獲取數據

-
-
-
-
- ) -} -``` - -### 4. 改善錯誤處理 - -```typescript -// 改善數據驗證 -if (judgesData.success && judgesData.data && judgesData.data.judges) { - setCompetitionJudges(judgesData.data.judges) - console.log('✅ 評審數據載入成功:', judgesData.data.judges.length, '個評審') -} else { - console.error('❌ 評審數據載入失敗:', judgesData.message || 'API回應格式錯誤') - setCompetitionJudges([]) -} -``` - -### 5. 創建調試工具 - -#### 調試頁面 (`app/debug-scoring/page.tsx`) -- 提供實時調試界面 -- 顯示詳細的載入日誌 -- 測試API端點回應 - -#### 資料庫測試腳本 (`scripts/test-db-connection.js`) -- 直接測試資料庫連接 -- 驗證數據存在性 - -#### API測試腳本 (`scripts/test-api-simple.js`) -- 測試API端點功能 -- 驗證數據格式 - -## 測試結果 - -### API測試結果 -```json -{ - "success": true, - "message": "競賽列表獲取成功", - "data": [ - { - "id": "be47d842-91f1-11f0-8595-bd825523ae01", - "name": "AA", - "type": "team", - "year": 2025, - "month": 9 - } - ] -} -``` - -### 資料庫測試結果 -``` -🏆 競賽: 1 個 (AA - team) -👨‍⚖️ 評審: 1 個 (aa - ITBU) -📱 應用: 1 個 (陳管理) -👥 團隊: 1 個 (aaa - 隊長: Wu Petty) -``` - -## 使用方式 - -### 1. 查看調試日誌 -打開瀏覽器開發者工具的Console,查看詳細的載入日誌: -- `🔄 開始載入競賽數據...` -- `📋 競賽API回應: {...}` -- `✅ 競賽數據載入成功: 1 個競賽` - -### 2. 使用調試頁面 -訪問 `http://localhost:3000/debug-scoring` 來: -- 實時查看數據載入過程 -- 測試API端點回應 -- 查看詳細的調試日誌 - -### 3. 檢查加載狀態 -- 初始載入時會顯示加載指示器 -- 數據載入完成後才會顯示評分表單 -- 選擇競賽後會載入對應的評審和參賽者 - -## 技術特點 - -- **完整的異步處理**:正確處理數據載入的異步特性 -- **用戶友好的加載狀態**:清楚顯示載入進度 -- **詳細的調試信息**:便於問題排查和修復 -- **錯誤恢復機制**:防止因API失敗導致的界面崩潰 -- **測試工具**:提供多種方式驗證系統狀態 - -## 預期結果 - -修復完成後,評分表單應該: -1. ✅ 正確載入競賽列表 -2. ✅ 顯示加載狀態指示器 -3. ✅ 在Console中輸出詳細的調試日誌 -4. ✅ 選擇競賽後載入評審和參賽者數據 -5. ✅ 提供可用的評審和參賽者選項 - -現在評分表單應該能夠正常工作,並且在Console中顯示詳細的調試信息! diff --git a/SCORING-FORM-FIX.md b/SCORING-FORM-FIX.md deleted file mode 100644 index 3f11965..0000000 --- a/SCORING-FORM-FIX.md +++ /dev/null @@ -1,118 +0,0 @@ -# 評分表單修復報告 - -## 問題描述 -手動評審評分表單無法選擇評審和參賽者,無法進行評分操作。 - -## 根本原因 -1. 前端組件使用空的mock數據而非從後端API獲取真實數據 -2. 評審和參賽者選項沒有與資料庫整合 -3. 缺少團隊評分支持 - -## 修復內容 - -### 1. 前端組件修復 (`components/admin/scoring-management.tsx`) - -#### 新增狀態管理 -```typescript -// 新增狀態:從後端獲取的評審和參賽者數據 -const [competitionJudges, setCompetitionJudges] = useState([]) -const [competitionParticipants, setCompetitionParticipants] = useState([]) -``` - -#### 新增數據載入函數 -```typescript -const loadCompetitionData = async () => { - // 載入競賽評審 - const judgesResponse = await fetch(`/api/competitions/${selectedCompetition.id}/judges`) - - // 載入競賽參賽者(應用和團隊) - const [appsResponse, teamsResponse] = await Promise.all([ - fetch(`/api/competitions/${selectedCompetition.id}/apps`), - fetch(`/api/competitions/${selectedCompetition.id}/teams`) - ]) -} -``` - -#### 更新評審選擇器 -- 從 `judges` 改為 `competitionJudges` -- 顯示評審的職稱和部門信息 - -#### 更新參賽者選擇器 -- 從mock數據改為 `competitionParticipants` -- 支持個人和團隊兩種參賽者類型 -- 顯示創作者/隊長信息 - -### 2. 後端API修復 - -#### 新增團隊評分支持 (`lib/services/database-service.ts`) -```typescript -// 提交團隊評分(使用應用評分表,但標記為團隊類型) -static async submitTeamScore(scoreData: Omit & { teamId: string }): Promise -``` - -#### 更新API端點 (`app/api/admin/scoring/route.ts`) -- 支持 `team` 參賽者類型 -- 根據參賽者類型選擇適當的評分方法 - -### 3. 評分提交邏輯修復 - -#### 動態參賽者類型判斷 -```typescript -const participantType = selectedParticipant?.type === 'individual' ? 'app' : - selectedParticipant?.type === 'team' ? 'team' : 'proposal' -``` - -## 修復後的功能 - -### ✅ 評審選擇 -- 從資料庫載入競賽的評審列表 -- 顯示評審姓名、職稱、部門 -- 支持選擇評審進行評分 - -### ✅ 參賽者選擇 -- 從資料庫載入競賽的應用和團隊 -- 支持個人賽和團隊賽參賽者 -- 顯示參賽者名稱和創作者信息 - -### ✅ 評分提交 -- 支持應用評分 (participantType: 'app') -- 支持提案評分 (participantType: 'proposal') -- 支持團隊評分 (participantType: 'team') -- 自動計算總分 -- 保存評審意見 - -### ✅ 數據整合 -- 完全與後端資料庫整合 -- 實時載入競賽相關數據 -- 支持評分記錄的CRUD操作 - -## 測試驗證 - -### 資料庫測試 -```bash -node scripts/test-scoring.js -``` - -### API功能測試 -```bash -node scripts/test-scoring-form.js -``` - -## 使用方式 - -1. 管理員選擇競賽 -2. 系統自動載入該競賽的評審和參賽者 -3. 點擊「手動輸入評分」 -4. 選擇評審和參賽者 -5. 填寫評分項目和意見 -6. 提交評分到資料庫 - -## 技術特點 - -- **完全整合**:前端與後端資料庫完全整合 -- **類型安全**:支持多種參賽者類型 -- **實時數據**:動態載入競賽相關數據 -- **用戶友好**:清晰的界面和錯誤提示 -- **可擴展**:易於添加新的評分類型 - -修復完成後,手動評審評分功能已完全可用,支持選擇評審和參賽者進行評分操作。 diff --git a/components/chat-bot.tsx b/components/chat-bot.tsx index 65236f3..38d540c 100644 --- a/components/chat-bot.tsx +++ b/components/chat-bot.tsx @@ -15,6 +15,7 @@ import { User, Loader2 } from "lucide-react" +import { generateSystemPrompt } from "@/lib/ai-knowledge-base" interface Message { id: string @@ -24,38 +25,10 @@ interface Message { quickQuestions?: string[] } -const DEEPSEEK_API_KEY = process.env.NEXT_PUBLIC_DEEPSEEK_API_KEY || "sk-3640dcff23fe4a069a64f536ac538d75" +const DEEPSEEK_API_KEY = process.env.NEXT_PUBLIC_DEEPSEEK_API_KEY || "sk-30cac9533e5b451fa1e277fe34a7f64b" const DEEPSEEK_API_URL = process.env.NEXT_PUBLIC_DEEPSEEK_API_URL || "https://api.deepseek.com/v1/chat/completions" -const systemPrompt = `你是一個競賽管理系統的AI助手,專門幫助用戶了解如何使用這個系統。 - -系統功能包括: - -後台管理功能: -1. 競賽管理 - 創建、編輯、刪除競賽 -2. 評審管理 - 管理評審團成員 -3. 評分系統 - 手動輸入評分或讓評審自行評分 -4. 團隊管理 - 管理參賽團隊 -5. 獎項管理 - 設定各種獎項 -6. 評審連結 - 提供評審登入連結 - -前台功能: -1. 競賽瀏覽 - 查看所有競賽資訊和詳細內容 -2. 團隊註冊 - 如何註冊參賽團隊和提交作品 -3. 作品展示 - 瀏覽參賽作品和投票功能 -4. 排行榜 - 查看人氣排行榜和得獎名單 -5. 個人中心 - 管理個人資料和參賽記錄 -6. 收藏功能 - 如何收藏喜歡的作品 -7. 評論系統 - 如何對作品進行評論和互動 -8. 搜尋功能 - 如何搜尋特定競賽或作品 -9. 通知系統 - 查看競賽更新和個人通知 -10. 幫助中心 - 常見問題和使用指南 - -請用友善、專業的語氣回答用戶問題,並提供具體的操作步驟。回答要簡潔明瞭,避免過長的文字。 - -重要:請不要使用任何Markdown格式,只使用純文字回答。不要使用**、*、#、-等符號。 - -回答時請使用繁體中文。` +const systemPrompt = generateSystemPrompt() export function ChatBot() { const [isOpen, setIsOpen] = useState(false) @@ -106,6 +79,15 @@ export function ChatBot() { const callDeepSeekAPI = async (userMessage: string): Promise => { try { + // 構建對話歷史,只保留最近的幾條對話 + const recentMessages = messages + .filter(msg => msg.sender === "user") + .slice(-5) // 只保留最近5條用戶消息 + .map(msg => ({ + role: "user" as const, + content: msg.text + })) + const response = await fetch(DEEPSEEK_API_URL, { method: "POST", headers: { @@ -119,31 +101,47 @@ export function ChatBot() { role: "system", content: systemPrompt }, - ...messages - .filter(msg => msg.sender === "user") - .map(msg => ({ - role: "user" as const, - content: msg.text - })), + ...recentMessages, { role: "user", content: userMessage } ], - max_tokens: 200, // 減少 token 數量以獲得更簡潔的回答 - temperature: 0.7 + max_tokens: 300, + temperature: 0.7, + stream: false }) }) if (!response.ok) { - throw new Error(`API request failed: ${response.status}`) + const errorText = await response.text() + console.error("API Error:", response.status, errorText) + throw new Error(`API request failed: ${response.status} - ${errorText}`) } const data = await response.json() - const rawResponse = data.choices[0]?.message?.content || "抱歉,我現在無法回答您的問題,請稍後再試。" + + if (!data.choices || !data.choices[0] || !data.choices[0].message) { + console.error("Invalid API response:", data) + throw new Error("Invalid API response format") + } + + const rawResponse = data.choices[0].message.content || "抱歉,我現在無法回答您的問題,請稍後再試。" return cleanResponse(rawResponse) } catch (error) { console.error("DeepSeek API error:", error) + + // 根據錯誤類型提供不同的錯誤信息 + if (error instanceof Error) { + if (error.message.includes('401')) { + return "API 密鑰無效,請聯繫管理員檢查配置。" + } else if (error.message.includes('429')) { + return "API 請求過於頻繁,請稍後再試。" + } else if (error.message.includes('500')) { + return "AI 服務暫時不可用,請稍後再試。" + } + } + return "抱歉,我現在無法連接到AI服務,請檢查網路連接或稍後再試。" } } @@ -153,48 +151,90 @@ export function ChatBot() { const question = userQuestion.toLowerCase() // 前台相關問題 - if (question.includes('註冊') || question.includes('團隊')) { + if (question.includes('註冊') || question.includes('團隊') || question.includes('報名')) { return [ "如何提交作品?", "怎麼查看競賽詳情?", - "如何收藏作品?", - "怎麼進行投票?" + "如何收藏應用?", + "怎麼查看我的參賽記錄?" ] } - if (question.includes('作品') || question.includes('提交')) { + if (question.includes('作品') || question.includes('提交') || question.includes('應用')) { return [ - "如何修改作品?", + "如何修改作品信息?", "怎麼查看作品狀態?", "如何刪除作品?", - "怎麼下載作品?" + "怎麼查看作品評價?" ] } - if (question.includes('投票') || question.includes('排行榜')) { + if (question.includes('投票') || question.includes('排行榜') || question.includes('評分')) { return [ "如何查看排行榜?", - "怎麼收藏作品?", - "如何評論作品?", - "怎麼分享作品?" + "怎麼收藏喜歡的應用?", + "如何對應用進行評論?", + "怎麼查看應用詳情?" + ] + } + if (question.includes('個人') || question.includes('資料') || question.includes('設置')) { + return [ + "如何修改個人資料?", + "怎麼查看我的收藏?", + "如何修改密碼?", + "怎麼查看通知?" ] } - // 後台相關問題 - if (question.includes('競賽') || question.includes('創建')) { + // 後台管理相關問題 + if (question.includes('競賽') || question.includes('創建') || question.includes('管理')) { return [ - "如何編輯競賽?", + "如何編輯競賽信息?", "怎麼設定評分標準?", "如何管理參賽團隊?", "怎麼設定獎項?" ] } - if (question.includes('評審') || question.includes('評分')) { + if (question.includes('評審') || question.includes('評分') || question.includes('評委')) { return [ - "如何新增評審?", + "如何新增評審成員?", "怎麼設定評審權限?", "如何查看評分結果?", "怎麼生成評審連結?" ] } + if (question.includes('應用') || question.includes('app') || question.includes('作品管理')) { + return [ + "如何審核應用?", + "怎麼管理應用狀態?", + "如何查看應用統計?", + "怎麼處理應用舉報?" + ] + } + if (question.includes('用戶') || question.includes('成員') || question.includes('邀請')) { + return [ + "如何邀請新用戶?", + "怎麼管理用戶角色?", + "如何查看用戶統計?", + "怎麼處理用戶問題?" + ] + } + + // 技術支持相關問題 + if (question.includes('忘記') || question.includes('密碼') || question.includes('登入')) { + return [ + "如何重設密碼?", + "怎麼修改個人資料?", + "如何聯繫管理員?", + "怎麼查看使用說明?" + ] + } + if (question.includes('錯誤') || question.includes('問題') || question.includes('無法')) { + return [ + "如何聯繫技術支持?", + "怎麼查看常見問題?", + "如何回報問題?", + "怎麼查看系統狀態?" + ] + } // 通用問題 return [ diff --git a/lib/ai-knowledge-base.ts b/lib/ai-knowledge-base.ts new file mode 100644 index 0000000..a78f9db --- /dev/null +++ b/lib/ai-knowledge-base.ts @@ -0,0 +1,253 @@ +// AI 助手知識庫 +export const platformKnowledge = { + // 平台概述 + overview: { + name: "強茂集團 AI 展示平台", + description: "企業內部 AI 應用展示與競賽管理系統", + purpose: "提供 AI 應用展示、競賽管理、評分系統和用戶互動功能" + }, + + // 主要功能模塊 + modules: { + // 前台功能 + frontend: { + "應用展示": { + description: "瀏覽和查看所有 AI 應用", + features: [ + "應用列表瀏覽", + "應用詳情查看", + "應用分類篩選", + "應用搜索功能", + "應用評分和評論" + ], + access: "所有用戶都可以訪問" + }, + "競賽系統": { + description: "參與和管理競賽", + features: [ + "競賽瀏覽和報名", + "作品提交", + "評分查看", + "排行榜查看", + "獎項展示" + ], + access: "註冊用戶可以參與" + }, + "用戶中心": { + description: "個人資料和活動管理", + features: [ + "個人資料管理", + "參賽記錄查看", + "收藏應用管理", + "通知查看", + "設置偏好" + ], + access: "需要登入" + } + }, + + // 後台管理功能 + backend: { + "應用管理": { + description: "管理平台上的所有 AI 應用", + features: [ + "應用列表查看(分頁顯示,每頁5個)", + "應用詳情管理", + "應用狀態管理(發布/下架)", + "應用統計數據", + "應用審核和批准" + ], + access: "管理員和開發者", + path: "/admin/apps" + }, + "競賽管理": { + description: "創建和管理競賽活動", + features: [ + "競賽創建和編輯", + "競賽類型設置(個人/團隊/混合)", + "競賽時間管理", + "參賽者管理", + "競賽規則設定" + ], + access: "管理員", + path: "/admin/competitions" + }, + "評審管理": { + description: "管理評審團和評分系統", + features: [ + "評審團成員管理", + "評分標準設定", + "評分進度追蹤", + "評分統計分析", + "評審連結生成" + ], + access: "管理員", + path: "/admin/judges" + }, + "用戶管理": { + description: "管理平台用戶", + features: [ + "用戶列表查看", + "用戶角色管理", + "用戶邀請功能", + "用戶統計數據", + "用戶活動監控" + ], + access: "管理員", + path: "/admin/users" + }, + "評分管理": { + description: "管理評分流程和結果", + features: [ + "手動評分輸入", + "評分進度監控", + "評分統計分析", + "評分報告生成", + "評分連結管理" + ], + access: "管理員", + path: "/admin/scoring" + } + } + }, + + // 詳細操作指南 + guides: { + "如何註冊參賽團隊": { + steps: [ + "1. 點擊首頁的「競賽」按鈕", + "2. 選擇要參加的競賽", + "3. 點擊「立即報名」按鈕", + "4. 填寫團隊信息(團隊名稱、成員信息等)", + "5. 確認報名信息並提交" + ], + tips: "確保所有團隊成員都已註冊平台帳號" + }, + "怎麼提交作品": { + steps: [ + "1. 登入您的帳號", + "2. 進入「我的競賽」頁面", + "3. 找到對應的競賽", + "4. 點擊「提交作品」", + "5. 填寫作品信息(名稱、描述、技術棧等)", + "6. 上傳作品文件或提供作品連結", + "7. 確認提交" + ], + tips: "作品提交後無法修改,請仔細檢查" + }, + "如何創建新競賽": { + steps: [ + "1. 以管理員身份登入", + "2. 進入「競賽管理」頁面", + "3. 點擊「新增競賽」按鈕", + "4. 填寫競賽基本信息(名稱、描述、類型等)", + "5. 設定競賽時間和規則", + "6. 配置評審團成員", + "7. 發布競賽" + ], + tips: "競賽發布前請仔細檢查所有設置" + }, + "怎麼管理評審團": { + steps: [ + "1. 進入「評審管理」頁面", + "2. 點擊「新增評審」", + "3. 填寫評審信息(姓名、職位、專業領域等)", + "4. 分配評審到特定競賽", + "5. 生成評審登入連結", + "6. 發送連結給評審" + ], + tips: "確保評審有足夠的專業知識來評分作品" + }, + "如何查看應用詳情": { + steps: [ + "1. 在首頁或應用列表中找到感興趣的應用", + "2. 點擊應用卡片或「查看詳情」按鈕", + "3. 在詳情頁面可以查看:", + " - 應用描述和功能", + " - 技術棧信息", + " - 創建者信息", + " - 用戶評價和評分", + " - 使用統計數據" + ] + }, + "如何收藏應用": { + steps: [ + "1. 進入應用詳情頁面", + "2. 點擊「收藏」按鈕(心形圖標)", + "3. 收藏的應用會出現在「我的收藏」中", + "4. 可以隨時取消收藏" + ] + }, + "如何進行評分": { + steps: [ + "1. 以評審身份登入", + "2. 使用管理員提供的評審連結", + "3. 選擇要評分的競賽", + "4. 查看參賽作品列表", + "5. 對每個作品進行評分(創新性、技術性、實用性、展示性、影響力)", + "6. 添加評分評論", + "7. 提交評分" + ], + tips: "評分標準:1-5分,5分為最高分" + } + }, + + // 常見問題 + faq: { + "忘記密碼怎麼辦": "點擊登入頁面的「忘記密碼」連結,輸入註冊時的電子郵件,系統會發送重設密碼的連結到您的信箱。", + "如何修改個人資料": "登入後點擊右上角頭像,選擇「個人資料」,即可修改姓名、部門、頭像等信息。", + "為什麼看不到某些競賽": "可能是因為競賽尚未開始、已結束,或者您沒有參與權限。請聯繫管理員確認。", + "評分什麼時候會公布": "評分結果會在競賽結束後由管理員統一公布,請關注平台通知。", + "如何聯繫管理員": "可以通過平台內的通知系統或直接發送郵件給管理員。", + "作品提交後可以修改嗎": "作品提交後無法修改,請在提交前仔細檢查所有信息。", + "如何查看我的參賽記錄": "登入後進入「我的競賽」頁面,可以查看所有參賽記錄和狀態。" + }, + + // 技術信息 + technical: { + "支持的瀏覽器": "Chrome、Firefox、Safari、Edge 最新版本", + "文件上傳限制": "單個文件最大 10MB,支持 JPG、PNG、PDF、DOC、PPT 等格式", + "系統要求": "需要 JavaScript 啟用,建議使用現代瀏覽器", + "數據安全": "所有數據都經過加密傳輸和存儲,符合企業安全標準" + } +} + +// 生成 AI 助手的系統提示詞 +export function generateSystemPrompt(): string { + return ` +你是一個專業的 AI 助手,專門為「${platformKnowledge.overview.name}」提供技術支持和用戶指導。 + +平台概述: +${platformKnowledge.overview.description} +${platformKnowledge.overview.purpose} + +主要功能模塊: + +前台功能: +${Object.entries(platformKnowledge.modules.frontend).map(([key, value]) => + `- ${key}: ${value.description}` +).join('\n')} + +後台管理功能: +${Object.entries(platformKnowledge.modules.backend).map(([key, value]) => + `- ${key}: ${value.description}` +).join('\n')} + +回答指南: +1. 用友善、專業的語氣回答用戶問題 +2. 提供具體的操作步驟和實用建議 +3. 回答要簡潔明瞭,避免過長的文字 +4. 如果問題涉及具體操作,請提供詳細步驟 +5. 如果不知道答案,請誠實說明並建議聯繫管理員 +6. 不要使用任何 Markdown 格式,只使用純文字回答 +7. 不要使用 **、*、#、- 等符號 +8. 回答長度控制在 200 字以內 + +常見問題快速回答: +${Object.entries(platformKnowledge.faq).map(([question, answer]) => + `Q: ${question}\nA: ${answer}` +).join('\n\n')} + +請根據用戶的問題,提供準確、有用的回答。 +` +} diff --git a/scripts/README.md b/scripts/README.md deleted file mode 100644 index 394084b..0000000 --- a/scripts/README.md +++ /dev/null @@ -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 個,建議使用簡化版本 diff --git a/scripts/check-app-competition-relation.js b/scripts/check-app-competition-relation.js deleted file mode 100644 index d0d644e..0000000 --- a/scripts/check-app-competition-relation.js +++ /dev/null @@ -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(); diff --git a/scripts/check-competition-data-details.js b/scripts/check-competition-data-details.js deleted file mode 100644 index 10b7150..0000000 --- a/scripts/check-competition-data-details.js +++ /dev/null @@ -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(); diff --git a/scripts/check-competition-data.js b/scripts/check-competition-data.js deleted file mode 100644 index b57ca11..0000000 --- a/scripts/check-competition-data.js +++ /dev/null @@ -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(); diff --git a/scripts/check-env.js b/scripts/check-env.js deleted file mode 100644 index 554248f..0000000 --- a/scripts/check-env.js +++ /dev/null @@ -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 不存在'); -} diff --git a/scripts/check-existing-apps.js b/scripts/check-existing-apps.js deleted file mode 100644 index 058b7d4..0000000 --- a/scripts/check-existing-apps.js +++ /dev/null @@ -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(); diff --git a/scripts/check-server.js b/scripts/check-server.js deleted file mode 100644 index d691258..0000000 --- a/scripts/check-server.js +++ /dev/null @@ -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(); diff --git a/scripts/clear-database.js b/scripts/clear-database.js deleted file mode 100644 index 5963c11..0000000 --- a/scripts/clear-database.js +++ /dev/null @@ -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); diff --git a/scripts/create-team-scores-table.js b/scripts/create-team-scores-table.js deleted file mode 100644 index e07abe0..0000000 --- a/scripts/create-team-scores-table.js +++ /dev/null @@ -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(); diff --git a/scripts/create-virtual-app-api.js b/scripts/create-virtual-app-api.js deleted file mode 100644 index 74dee08..0000000 --- a/scripts/create-virtual-app-api.js +++ /dev/null @@ -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(); diff --git a/scripts/create-virtual-app-simple.sql b/scripts/create-virtual-app-simple.sql deleted file mode 100644 index d3671e9..0000000 --- a/scripts/create-virtual-app-simple.sql +++ /dev/null @@ -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'; diff --git a/scripts/create-virtual-apps-api.js b/scripts/create-virtual-apps-api.js deleted file mode 100644 index b13797d..0000000 --- a/scripts/create-virtual-apps-api.js +++ /dev/null @@ -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(); diff --git a/scripts/create-virtual-apps.js b/scripts/create-virtual-apps.js deleted file mode 100644 index 7889e4c..0000000 --- a/scripts/create-virtual-apps.js +++ /dev/null @@ -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(); diff --git a/scripts/fix-foreign-key-constraint.sql b/scripts/fix-foreign-key-constraint.sql deleted file mode 100644 index bece863..0000000 --- a/scripts/fix-foreign-key-constraint.sql +++ /dev/null @@ -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'; diff --git a/scripts/populate-sample-data.js b/scripts/populate-sample-data.js deleted file mode 100644 index ec41f06..0000000 --- a/scripts/populate-sample-data.js +++ /dev/null @@ -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 }; diff --git a/scripts/quick-fix.sql b/scripts/quick-fix.sql deleted file mode 100644 index 9e61f1e..0000000 --- a/scripts/quick-fix.sql +++ /dev/null @@ -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'; diff --git a/scripts/redesign-scoring-database.sql b/scripts/redesign-scoring-database.sql deleted file mode 100644 index b8f3390..0000000 --- a/scripts/redesign-scoring-database.sql +++ /dev/null @@ -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; diff --git a/scripts/test-invitation-link.js b/scripts/test-invitation-link.js deleted file mode 100644 index 2cca5a1..0000000 --- a/scripts/test-invitation-link.js +++ /dev/null @@ -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'); diff --git a/scripts/test-scoring-progress.js b/scripts/test-scoring-progress.js deleted file mode 100644 index 6fdbba6..0000000 --- a/scripts/test-scoring-progress.js +++ /dev/null @@ -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(); diff --git a/scripts/test-scoring-summary.js b/scripts/test-scoring-summary.js deleted file mode 100644 index 35c443b..0000000 --- a/scripts/test-scoring-summary.js +++ /dev/null @@ -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();