實作管理者儀表板、刪除不必要說明文件
This commit is contained in:
@@ -1,187 +0,0 @@
|
|||||||
# 管理員存取被拒問題修復總結
|
|
||||||
|
|
||||||
## 🎯 問題描述
|
|
||||||
|
|
||||||
管理員使用正確的帳號密碼登入後,訪問管理員後台時仍然顯示「存取被拒」錯誤。
|
|
||||||
|
|
||||||
## 🔍 問題分析
|
|
||||||
|
|
||||||
### 根本原因:
|
|
||||||
1. **服務器端渲染問題**:Next.js 在服務器端渲染時,`localStorage` 不可用
|
|
||||||
2. **客戶端 hydration 時機**:用戶狀態需要等待客戶端載入 `localStorage` 資料
|
|
||||||
3. **權限檢查邏輯**:在用戶狀態未載入時就進行權限檢查
|
|
||||||
|
|
||||||
### 問題流程:
|
|
||||||
1. 用戶訪問 `/admin` 頁面
|
|
||||||
2. 服務器端渲染時,`localStorage` 不可用,`user` 為 `null`
|
|
||||||
3. 權限檢查 `!user || user.role !== "admin"` 返回 `true`
|
|
||||||
4. 顯示「存取被拒」頁面
|
|
||||||
5. 客戶端 hydration 後,用戶狀態載入,但頁面已經渲染
|
|
||||||
|
|
||||||
## ✅ 修復方案
|
|
||||||
|
|
||||||
### 1. 添加初始化狀態管理
|
|
||||||
**文件:** `contexts/auth-context.tsx`
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
// 添加初始化狀態
|
|
||||||
const [isInitialized, setIsInitialized] = useState(false)
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
// Check for stored user session only on client side
|
|
||||||
if (typeof window !== 'undefined') {
|
|
||||||
const storedUser = localStorage.getItem("user")
|
|
||||||
if (storedUser) {
|
|
||||||
setUser(JSON.parse(storedUser))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
setIsLoading(false)
|
|
||||||
setIsInitialized(true) // 標記為已初始化
|
|
||||||
}, [])
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. 改進權限檢查邏輯
|
|
||||||
**文件:** `components/admin/admin-layout.tsx`
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
// 如果還在載入中或未初始化,顯示載入畫面
|
|
||||||
if (!isClient || isLoading || !isInitialized) {
|
|
||||||
return (
|
|
||||||
<div className="min-h-screen flex items-center justify-center bg-gray-100">
|
|
||||||
<div className="text-center space-y-4">
|
|
||||||
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600 mx-auto"></div>
|
|
||||||
<p className="text-gray-600">載入中...</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 檢查用戶權限
|
|
||||||
if (!user || user.role !== "admin") {
|
|
||||||
return (
|
|
||||||
<div className="min-h-screen flex items-center justify-center bg-gray-100">
|
|
||||||
<div className="text-center space-y-4">
|
|
||||||
<div className="w-16 h-16 bg-red-100 rounded-full flex items-center justify-center mx-auto">
|
|
||||||
<AlertTriangle className="w-8 h-8 text-red-600" />
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<h2 className="text-2xl font-bold text-gray-900 mb-2">存取被拒</h2>
|
|
||||||
<p className="text-gray-600 mb-4">您沒有管理員權限訪問此頁面</p>
|
|
||||||
{process.env.NODE_ENV === 'development' && (
|
|
||||||
<div className="text-xs text-gray-500 mb-4">
|
|
||||||
調試信息: 用戶={user ? '已登入' : '未登入'}, 角色={user?.role || '無'}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{/* ... 其他內容 ... */}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3. 添加調試信息
|
|
||||||
在開發環境中添加調試信息,幫助診斷問題:
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
{process.env.NODE_ENV === 'development' && (
|
|
||||||
<div className="text-xs text-gray-500 mb-4">
|
|
||||||
調試信息: 用戶={user ? '已登入' : '未登入'}, 角色={user?.role || '無'}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 🧪 測試結果
|
|
||||||
|
|
||||||
### 測試腳本:`scripts/test-complete-admin-flow.js`
|
|
||||||
|
|
||||||
```
|
|
||||||
✅ 登入頁面載入成功
|
|
||||||
✅ 管理員登入成功
|
|
||||||
用戶資料: {
|
|
||||||
id: 'c8b26413-00b9-4337-870d-4e37e3e8e375',
|
|
||||||
name: '系統管理員',
|
|
||||||
email: 'admin@ai-platform.com',
|
|
||||||
role: 'admin'
|
|
||||||
}
|
|
||||||
✅ 頁面顯示載入中狀態(正常)
|
|
||||||
```
|
|
||||||
|
|
||||||
### 修復驗證:
|
|
||||||
- ✅ 管理員登入 API 正常工作
|
|
||||||
- ✅ 用戶角色正確設置為 `admin`
|
|
||||||
- ✅ 頁面顯示載入中狀態(等待客戶端 hydration)
|
|
||||||
- ✅ 添加了調試信息幫助診斷
|
|
||||||
|
|
||||||
## 📋 修復內容總結
|
|
||||||
|
|
||||||
### ✅ 已修復的問題:
|
|
||||||
|
|
||||||
1. **AuthContext 組件**
|
|
||||||
- 添加 `isInitialized` 狀態管理
|
|
||||||
- 改進客戶端狀態載入邏輯
|
|
||||||
- 確保服務器端和客戶端渲染一致
|
|
||||||
|
|
||||||
2. **AdminLayout 組件**
|
|
||||||
- 添加載入狀態檢查
|
|
||||||
- 改進權限檢查邏輯
|
|
||||||
- 添加調試信息顯示
|
|
||||||
|
|
||||||
3. **權限檢查流程**
|
|
||||||
- 等待客戶端初始化完成
|
|
||||||
- 確保用戶狀態正確載入
|
|
||||||
- 提供清晰的錯誤信息
|
|
||||||
|
|
||||||
### 🔧 技術改進:
|
|
||||||
|
|
||||||
1. **狀態管理**:使用 `isInitialized` 狀態確保客戶端載入完成
|
|
||||||
2. **載入狀態**:顯示載入中畫面而不是錯誤頁面
|
|
||||||
3. **調試支持**:在開發環境中提供調試信息
|
|
||||||
4. **用戶體驗**:提供清晰的載入和錯誤狀態
|
|
||||||
|
|
||||||
## 🎉 修復效果
|
|
||||||
|
|
||||||
### 修復前:
|
|
||||||
- 管理員登入後仍顯示「存取被拒」
|
|
||||||
- 服務器端和客戶端渲染不一致
|
|
||||||
- 無法診斷問題原因
|
|
||||||
|
|
||||||
### 修復後:
|
|
||||||
- 頁面正確顯示載入中狀態
|
|
||||||
- 等待客戶端載入用戶資料
|
|
||||||
- 提供調試信息幫助診斷
|
|
||||||
- 權限檢查邏輯更加健壯
|
|
||||||
|
|
||||||
## 🚀 使用方式
|
|
||||||
|
|
||||||
### 1. 測試修復效果
|
|
||||||
```bash
|
|
||||||
# 測試完整管理員流程
|
|
||||||
node scripts/test-complete-admin-flow.js
|
|
||||||
|
|
||||||
# 測試管理員存取修復
|
|
||||||
node scripts/test-admin-fix.js
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. 驗證修復
|
|
||||||
1. 打開瀏覽器訪問 `http://localhost:3000`
|
|
||||||
2. 使用管理員帳號登入:
|
|
||||||
- 電子郵件:`admin@ai-platform.com`
|
|
||||||
- 密碼:`admin123456`
|
|
||||||
3. 登入後訪問 `http://localhost:3000/admin`
|
|
||||||
4. 確認頁面正常載入管理員後台
|
|
||||||
|
|
||||||
## 📝 注意事項
|
|
||||||
|
|
||||||
1. **登入流程**:用戶需要先登入才能訪問管理員頁面
|
|
||||||
2. **載入時間**:首次訪問可能需要等待客戶端載入
|
|
||||||
3. **調試信息**:開發環境中會顯示調試信息
|
|
||||||
4. **權限檢查**:確保用戶角色為 `admin`
|
|
||||||
|
|
||||||
## 🔍 預防措施
|
|
||||||
|
|
||||||
1. **狀態管理**:使用適當的狀態管理確保客戶端載入完成
|
|
||||||
2. **權限檢查**:在用戶狀態載入後再進行權限檢查
|
|
||||||
3. **載入狀態**:提供清晰的載入和錯誤狀態
|
|
||||||
4. **調試支持**:在開發環境中提供調試信息
|
|
||||||
|
|
||||||
管理員存取被拒問題已修復,現在管理員可以正常訪問後台!
|
|
@@ -1,143 +0,0 @@
|
|||||||
# 用戶認證系統整合總結
|
|
||||||
|
|
||||||
## 🎯 完成的工作
|
|
||||||
|
|
||||||
### 1. 資料庫 API 端點 ✅
|
|
||||||
- **`/api/auth/login`** - 用戶登入
|
|
||||||
- **`/api/auth/register`** - 用戶註冊
|
|
||||||
- **`/api/auth/profile`** - 用戶資料管理
|
|
||||||
|
|
||||||
### 2. 資料庫服務層 ✅
|
|
||||||
- 更新 `UserService` 類別,支援實例方法和靜態方法
|
|
||||||
- 密碼加密使用 `bcryptjs` (12 rounds)
|
|
||||||
- 完整的 CRUD 操作
|
|
||||||
|
|
||||||
### 3. 前端整合 ✅
|
|
||||||
- 更新 `AuthContext` 以使用資料庫 API
|
|
||||||
- 保持向後兼容性,支援現有功能
|
|
||||||
- 錯誤處理和載入狀態管理
|
|
||||||
|
|
||||||
### 4. 測試帳號生成 ✅
|
|
||||||
創建了 5 個測試帳號:
|
|
||||||
|
|
||||||
| 角色 | 電子郵件 | 密碼 | 部門 | 描述 |
|
|
||||||
|------|----------|------|------|------|
|
|
||||||
| **管理員** | admin@ai-platform.com | admin123456 | ITBU | 系統管理員,擁有所有權限 |
|
|
||||||
| **開發者** | developer@ai-platform.com | dev123456 | ITBU | 開發者,可以提交應用和提案 |
|
|
||||||
| **一般用戶** | user@ai-platform.com | user123456 | MBU1 | 一般用戶,可以瀏覽和評分 |
|
|
||||||
| **評委** | judge@ai-platform.com | judge123456 | HQBU | 評委,可以評分應用和提案 |
|
|
||||||
| **團隊負責人** | team-lead@ai-platform.com | team123456 | SBU | 團隊負責人 |
|
|
||||||
|
|
||||||
## 🔧 技術實現
|
|
||||||
|
|
||||||
### 密碼安全
|
|
||||||
- 使用 `bcryptjs` 進行密碼加密
|
|
||||||
- 12 rounds 的 salt 強度
|
|
||||||
- 密碼長度最少 6 個字符
|
|
||||||
|
|
||||||
### 資料庫結構
|
|
||||||
```sql
|
|
||||||
CREATE TABLE `users` (
|
|
||||||
`id` VARCHAR(36) PRIMARY KEY,
|
|
||||||
`name` VARCHAR(100) NOT NULL,
|
|
||||||
`email` VARCHAR(255) UNIQUE NOT NULL,
|
|
||||||
`password_hash` VARCHAR(255) NOT NULL,
|
|
||||||
`avatar` VARCHAR(500) NULL,
|
|
||||||
`department` VARCHAR(100) NOT NULL,
|
|
||||||
`role` ENUM('user', 'developer', 'admin') DEFAULT 'user',
|
|
||||||
`join_date` DATE NOT NULL,
|
|
||||||
`total_likes` INT DEFAULT 0,
|
|
||||||
`total_views` INT DEFAULT 0,
|
|
||||||
`is_active` BOOLEAN DEFAULT TRUE,
|
|
||||||
`last_login` TIMESTAMP NULL,
|
|
||||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
||||||
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
|
||||||
);
|
|
||||||
```
|
|
||||||
|
|
||||||
### API 端點詳情
|
|
||||||
|
|
||||||
#### POST /api/auth/login
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"email": "user@example.com",
|
|
||||||
"password": "password123"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**回應:**
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"success": true,
|
|
||||||
"user": {
|
|
||||||
"id": "uuid",
|
|
||||||
"name": "用戶名稱",
|
|
||||||
"email": "user@example.com",
|
|
||||||
"role": "user",
|
|
||||||
"department": "ITBU",
|
|
||||||
// ... 其他用戶資訊(不包含密碼)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### POST /api/auth/register
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"name": "用戶名稱",
|
|
||||||
"email": "user@example.com",
|
|
||||||
"password": "password123",
|
|
||||||
"department": "ITBU",
|
|
||||||
"role": "user" // 可選,預設為 "user"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### PUT /api/auth/profile
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"userId": "user-uuid",
|
|
||||||
"name": "新名稱",
|
|
||||||
"department": "新部門"
|
|
||||||
// ... 其他可更新欄位
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 🚀 使用方法
|
|
||||||
|
|
||||||
### 1. 啟動開發服務器
|
|
||||||
```bash
|
|
||||||
pnpm run dev
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. 創建測試用戶(可選)
|
|
||||||
```bash
|
|
||||||
pnpm run create:users
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3. 測試資料庫連接
|
|
||||||
```bash
|
|
||||||
pnpm run test:db
|
|
||||||
```
|
|
||||||
|
|
||||||
### 4. 測試認證功能
|
|
||||||
```bash
|
|
||||||
node scripts/test-db-auth.js
|
|
||||||
```
|
|
||||||
|
|
||||||
## 🔐 安全特性
|
|
||||||
|
|
||||||
1. **密碼加密**:使用 bcryptjs 進行安全的密碼雜湊
|
|
||||||
2. **SQL 注入防護**:使用參數化查詢
|
|
||||||
3. **重複註冊防護**:檢查電子郵件唯一性
|
|
||||||
4. **輸入驗證**:API 端點包含完整的輸入驗證
|
|
||||||
5. **錯誤處理**:統一的錯誤回應格式
|
|
||||||
|
|
||||||
## 📝 注意事項
|
|
||||||
|
|
||||||
1. **環境變數**:確保 `.env.local` 包含正確的資料庫連接資訊
|
|
||||||
2. **密碼強度**:建議使用更強的密碼策略
|
|
||||||
3. **會話管理**:目前使用 localStorage,生產環境建議使用 JWT 或 session
|
|
||||||
4. **權限控制**:角色權限檢查在前端實現,後端需要額外的中間件
|
|
||||||
|
|
||||||
## 🎉 整合完成
|
|
||||||
|
|
||||||
用戶認證系統已成功從 `localStorage` 遷移到 MySQL 資料庫,所有測試帳號已創建,API 端點正常運作。您現在可以使用任何測試帳號登入系統進行測試!
|
|
@@ -1,296 +0,0 @@
|
|||||||
# AI智能助手 (ChatBot) 組件分析
|
|
||||||
|
|
||||||
## 1. 組件概述
|
|
||||||
|
|
||||||
### 1.1 功能定位
|
|
||||||
AI智能助手是一個內嵌的聊天機器人組件,為用戶提供即時的系統使用指導和問題解答服務。
|
|
||||||
|
|
||||||
### 1.2 核心特性
|
|
||||||
- **即時對話**: 與AI助手進行自然語言對話
|
|
||||||
- **智能回答**: 基於DeepSeek API的智能回應
|
|
||||||
- **快速問題**: 提供相關問題的快速選擇
|
|
||||||
- **上下文記憶**: 保持對話的連續性
|
|
||||||
|
|
||||||
## 2. 技術實現
|
|
||||||
|
|
||||||
### 2.1 技術棧
|
|
||||||
```typescript
|
|
||||||
// 核心技術
|
|
||||||
- React 19 (Hooks)
|
|
||||||
- TypeScript 5
|
|
||||||
- DeepSeek Chat API
|
|
||||||
- Tailwind CSS
|
|
||||||
- shadcn/ui 組件庫
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2.2 組件結構
|
|
||||||
```typescript
|
|
||||||
// 主要接口定義
|
|
||||||
interface Message {
|
|
||||||
id: string
|
|
||||||
text: string
|
|
||||||
sender: "user" | "bot"
|
|
||||||
timestamp: Date
|
|
||||||
quickQuestions?: string[]
|
|
||||||
}
|
|
||||||
|
|
||||||
// 組件狀態
|
|
||||||
const [isOpen, setIsOpen] = useState(false) // 對話框開關
|
|
||||||
const [messages, setMessages] = useState<Message[]>() // 訊息列表
|
|
||||||
const [inputValue, setInputValue] = useState("") // 輸入值
|
|
||||||
const [isTyping, setIsTyping] = useState(false) // 打字狀態
|
|
||||||
const [isLoading, setIsLoading] = useState(false) // 載入狀態
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2.3 API整合
|
|
||||||
```typescript
|
|
||||||
// DeepSeek API 配置
|
|
||||||
const DEEPSEEK_API_KEY = "sk-3640dcff23fe4a069a64f536ac538d75"
|
|
||||||
const DEEPSEEK_API_URL = "https://api.deepseek.com/v1/chat/completions"
|
|
||||||
|
|
||||||
// API 調用函數
|
|
||||||
const callDeepSeekAPI = async (userMessage: string): Promise<string> => {
|
|
||||||
// 實現細節...
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 3. 功能詳解
|
|
||||||
|
|
||||||
### 3.1 對話能力
|
|
||||||
|
|
||||||
#### 3.1.1 前台功能指導
|
|
||||||
- **註冊流程**: 如何註冊參賽團隊
|
|
||||||
- **作品提交**: 如何提交和管理作品
|
|
||||||
- **投票系統**: 如何參與投票和收藏
|
|
||||||
- **個人中心**: 如何管理個人資料
|
|
||||||
|
|
||||||
#### 3.1.2 後台管理協助
|
|
||||||
- **競賽創建**: 如何創建和管理競賽
|
|
||||||
- **評審管理**: 如何管理評審團成員
|
|
||||||
- **評分系統**: 如何設定評分標準
|
|
||||||
- **獎項設定**: 如何配置獎項類型
|
|
||||||
|
|
||||||
#### 3.1.3 系統使用指南
|
|
||||||
- **操作步驟**: 提供具體的操作指引
|
|
||||||
- **常見問題**: 解答用戶常見疑問
|
|
||||||
- **最佳實踐**: 推薦最佳使用方法
|
|
||||||
|
|
||||||
### 3.2 智能特性
|
|
||||||
|
|
||||||
#### 3.2.1 內容清理
|
|
||||||
```typescript
|
|
||||||
const cleanResponse = (text: string): string => {
|
|
||||||
return text
|
|
||||||
// 移除 Markdown 格式
|
|
||||||
.replace(/\*\*(.*?)\*\*/g, '$1')
|
|
||||||
.replace(/\*(.*?)\*/g, '$1')
|
|
||||||
.replace(/`(.*?)`/g, '$1')
|
|
||||||
.replace(/#{1,6}\s/g, '')
|
|
||||||
.replace(/^- /g, '• ')
|
|
||||||
.replace(/^\d+\.\s/g, '')
|
|
||||||
// 移除多餘空行
|
|
||||||
.replace(/\n\s*\n\s*\n/g, '\n\n')
|
|
||||||
// 限制文字長度
|
|
||||||
.slice(0, 300)
|
|
||||||
.trim()
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 3.2.2 快速問題生成
|
|
||||||
```typescript
|
|
||||||
const generateQuickQuestions = (userQuestion: string): string[] => {
|
|
||||||
const question = userQuestion.toLowerCase()
|
|
||||||
|
|
||||||
// 根據問題類型生成相關建議
|
|
||||||
if (question.includes('註冊') || question.includes('團隊')) {
|
|
||||||
return [
|
|
||||||
"如何提交作品?",
|
|
||||||
"怎麼查看競賽詳情?",
|
|
||||||
"如何收藏作品?",
|
|
||||||
"怎麼進行投票?"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
// 更多邏輯...
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3.3 用戶體驗
|
|
||||||
|
|
||||||
#### 3.3.1 界面設計
|
|
||||||
- **浮動按鈕**: 固定在右下角的聊天入口
|
|
||||||
- **模態對話框**: 全屏遮罩的聊天界面
|
|
||||||
- **響應式設計**: 適配不同螢幕尺寸
|
|
||||||
- **無障礙設計**: 支持鍵盤導航
|
|
||||||
|
|
||||||
#### 3.3.2 交互體驗
|
|
||||||
- **即時反饋**: 輸入狀態和載入動畫
|
|
||||||
- **自動滾動**: 新訊息自動滾動到底部
|
|
||||||
- **快捷操作**: Enter鍵發送訊息
|
|
||||||
- **錯誤處理**: 網路錯誤的優雅處理
|
|
||||||
|
|
||||||
## 4. 系統提示詞 (System Prompt)
|
|
||||||
|
|
||||||
### 4.1 提示詞結構
|
|
||||||
```typescript
|
|
||||||
const systemPrompt = `你是一個競賽管理系統的AI助手,專門幫助用戶了解如何使用這個系統。
|
|
||||||
|
|
||||||
系統功能包括:
|
|
||||||
|
|
||||||
後台管理功能:
|
|
||||||
1. 競賽管理 - 創建、編輯、刪除競賽
|
|
||||||
2. 評審管理 - 管理評審團成員
|
|
||||||
3. 評分系統 - 手動輸入評分或讓評審自行評分
|
|
||||||
4. 團隊管理 - 管理參賽團隊
|
|
||||||
5. 獎項管理 - 設定各種獎項
|
|
||||||
6. 評審連結 - 提供評審登入連結
|
|
||||||
|
|
||||||
前台功能:
|
|
||||||
1. 競賽瀏覽 - 查看所有競賽資訊和詳細內容
|
|
||||||
2. 團隊註冊 - 如何註冊參賽團隊和提交作品
|
|
||||||
3. 作品展示 - 瀏覽參賽作品和投票功能
|
|
||||||
4. 排行榜 - 查看人氣排行榜和得獎名單
|
|
||||||
5. 個人中心 - 管理個人資料和參賽記錄
|
|
||||||
6. 收藏功能 - 如何收藏喜歡的作品
|
|
||||||
7. 評論系統 - 如何對作品進行評論和互動
|
|
||||||
8. 搜尋功能 - 如何搜尋特定競賽或作品
|
|
||||||
9. 通知系統 - 查看競賽更新和個人通知
|
|
||||||
10. 幫助中心 - 常見問題和使用指南
|
|
||||||
|
|
||||||
請用友善、專業的語氣回答用戶問題,並提供具體的操作步驟。回答要簡潔明瞭,避免過長的文字。
|
|
||||||
|
|
||||||
重要:請不要使用任何Markdown格式,只使用純文字回答。不要使用**、*、#、-等符號。
|
|
||||||
|
|
||||||
回答時請使用繁體中文。`
|
|
||||||
```
|
|
||||||
|
|
||||||
### 4.2 回答規範
|
|
||||||
- **語言**: 繁體中文
|
|
||||||
- **格式**: 純文字,無Markdown
|
|
||||||
- **長度**: 限制在300字以內
|
|
||||||
- **語氣**: 友善、專業
|
|
||||||
- **內容**: 具體操作步驟
|
|
||||||
|
|
||||||
## 5. 錯誤處理
|
|
||||||
|
|
||||||
### 5.1 API錯誤處理
|
|
||||||
```typescript
|
|
||||||
try {
|
|
||||||
const response = await fetch(DEEPSEEK_API_URL, {
|
|
||||||
// API 調用配置...
|
|
||||||
})
|
|
||||||
|
|
||||||
if (!response.ok) {
|
|
||||||
throw new Error(`API request failed: ${response.status}`)
|
|
||||||
}
|
|
||||||
|
|
||||||
const data = await response.json()
|
|
||||||
return cleanResponse(data.choices[0]?.message?.content || "抱歉,我現在無法回答您的問題,請稍後再試。")
|
|
||||||
} catch (error) {
|
|
||||||
console.error("DeepSeek API error:", error)
|
|
||||||
return "抱歉,我現在無法連接到AI服務,請檢查網路連接或稍後再試。"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 5.2 用戶體驗錯誤處理
|
|
||||||
- **網路錯誤**: 提示檢查網路連接
|
|
||||||
- **API限制**: 提示稍後再試
|
|
||||||
- **輸入驗證**: 防止空訊息發送
|
|
||||||
- **載入狀態**: 防止重複發送
|
|
||||||
|
|
||||||
## 6. 性能優化
|
|
||||||
|
|
||||||
### 6.1 API優化
|
|
||||||
```typescript
|
|
||||||
// 限制token數量以獲得更簡潔的回答
|
|
||||||
max_tokens: 200,
|
|
||||||
temperature: 0.7
|
|
||||||
```
|
|
||||||
|
|
||||||
### 6.2 組件優化
|
|
||||||
- **訊息虛擬化**: 大量訊息時的效能優化
|
|
||||||
- **防抖處理**: 避免頻繁API調用
|
|
||||||
- **記憶化**: 重複問題的快取處理
|
|
||||||
- **懶加載**: 按需載入組件
|
|
||||||
|
|
||||||
## 7. 安全考量
|
|
||||||
|
|
||||||
### 7.1 API密鑰安全
|
|
||||||
- **環境變數**: API密鑰存儲在環境變數中
|
|
||||||
- **加密存儲**: 敏感資訊加密處理
|
|
||||||
- **訪問控制**: 限制API調用頻率
|
|
||||||
|
|
||||||
### 7.2 數據隱私
|
|
||||||
- **聊天記錄**: 本地存儲,不上傳服務器
|
|
||||||
- **個人資訊**: 不收集敏感個人資訊
|
|
||||||
- **數據清理**: 定期清理過期數據
|
|
||||||
|
|
||||||
## 8. 擴展性設計
|
|
||||||
|
|
||||||
### 8.1 多語言支持
|
|
||||||
```typescript
|
|
||||||
interface LocalizationConfig {
|
|
||||||
language: string
|
|
||||||
systemPrompt: Record<string, string>
|
|
||||||
quickQuestions: Record<string, string[]>
|
|
||||||
errorMessages: Record<string, string>
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 8.2 多AI模型支持
|
|
||||||
```typescript
|
|
||||||
interface AIModelConfig {
|
|
||||||
provider: 'deepseek' | 'openai' | 'anthropic'
|
|
||||||
model: string
|
|
||||||
apiKey: string
|
|
||||||
apiUrl: string
|
|
||||||
maxTokens: number
|
|
||||||
temperature: number
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 8.3 自定義功能
|
|
||||||
- **知識庫整合**: 連接企業知識庫
|
|
||||||
- **FAQ系統**: 自動回答常見問題
|
|
||||||
- **工單系統**: 複雜問題轉人工處理
|
|
||||||
- **分析報告**: 聊天數據分析
|
|
||||||
|
|
||||||
## 9. 使用指南
|
|
||||||
|
|
||||||
### 9.1 基本使用
|
|
||||||
1. 點擊右下角的聊天按鈕
|
|
||||||
2. 在輸入框中輸入問題
|
|
||||||
3. 按Enter鍵或點擊發送按鈕
|
|
||||||
4. 查看AI助手的回答
|
|
||||||
5. 點擊快速問題進行後續對話
|
|
||||||
|
|
||||||
### 9.2 進階功能
|
|
||||||
- **上下文記憶**: 對話會保持上下文
|
|
||||||
- **快速問題**: 點擊建議問題快速提問
|
|
||||||
- **錯誤重試**: 網路錯誤時可重新發送
|
|
||||||
- **對話重置**: 關閉重開可開始新對話
|
|
||||||
|
|
||||||
### 9.3 最佳實踐
|
|
||||||
- **具體問題**: 提出具體明確的問題
|
|
||||||
- **分步驟**: 複雜操作分步驟詢問
|
|
||||||
- **耐心等待**: AI需要時間處理複雜問題
|
|
||||||
- **反饋提供**: 對回答不滿意時可重新提問
|
|
||||||
|
|
||||||
## 10. 未來規劃
|
|
||||||
|
|
||||||
### 10.1 短期目標
|
|
||||||
- [ ] 添加語音輸入功能
|
|
||||||
- [ ] 支持圖片上傳和識別
|
|
||||||
- [ ] 增加更多快速問題模板
|
|
||||||
- [ ] 優化回答品質和速度
|
|
||||||
|
|
||||||
### 10.2 長期目標
|
|
||||||
- [ ] 整合企業知識庫
|
|
||||||
- [ ] 支持多語言對話
|
|
||||||
- [ ] 添加情感分析功能
|
|
||||||
- [ ] 實現智能推薦系統
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**文檔版本**: v1.0
|
|
||||||
**最後更新**: 2024年12月
|
|
||||||
**負責人**: 前端開發團隊
|
|
@@ -1,141 +0,0 @@
|
|||||||
# 忘記密碼功能實現總結
|
|
||||||
|
|
||||||
## 🎯 功能概述
|
|
||||||
|
|
||||||
已成功實現完整的忘記密碼功能,包括前端界面、後端 API、資料庫支援和郵件發送。
|
|
||||||
|
|
||||||
## ✅ 實現的功能
|
|
||||||
|
|
||||||
### 1. 資料庫支援
|
|
||||||
- **密碼重設 tokens 表**:存儲重設 token 和過期時間
|
|
||||||
- **外鍵關聯**:與 users 表關聯,支援級聯刪除
|
|
||||||
- **索引優化**:針對查詢性能優化
|
|
||||||
|
|
||||||
### 2. 後端 API
|
|
||||||
- **`/api/auth/forgot-password`**:發送重設郵件
|
|
||||||
- **`/api/auth/reset-password`**:驗證 token 並重設密碼
|
|
||||||
|
|
||||||
### 3. 前端界面
|
|
||||||
- **忘記密碼對話框**:整合到登入流程
|
|
||||||
- **密碼重設頁面**:`/reset-password` 專用頁面
|
|
||||||
- **完整的表單驗證**:密碼強度和確認驗證
|
|
||||||
|
|
||||||
### 4. 郵件服務
|
|
||||||
- **HTML 郵件模板**:美觀的重設郵件
|
|
||||||
- **SMTP 配置**:支援多種郵件服務商
|
|
||||||
- **安全 token**:UUID + 時間戳生成
|
|
||||||
|
|
||||||
## 🔧 技術實現
|
|
||||||
|
|
||||||
### 資料庫結構
|
|
||||||
```sql
|
|
||||||
CREATE TABLE password_reset_tokens (
|
|
||||||
id VARCHAR(36) PRIMARY KEY,
|
|
||||||
user_id VARCHAR(36) NOT NULL,
|
|
||||||
token VARCHAR(255) NOT NULL UNIQUE,
|
|
||||||
expires_at TIMESTAMP NOT NULL,
|
|
||||||
used_at TIMESTAMP NULL,
|
|
||||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
||||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
||||||
|
|
||||||
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
|
|
||||||
);
|
|
||||||
```
|
|
||||||
|
|
||||||
### API 端點
|
|
||||||
|
|
||||||
#### POST /api/auth/forgot-password
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"email": "user@example.com"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**回應:**
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"success": true,
|
|
||||||
"message": "密碼重設連結已發送到您的電子郵件"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### POST /api/auth/reset-password
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"token": "reset-token",
|
|
||||||
"password": "newpassword123"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### GET /api/auth/reset-password?token=xxx
|
|
||||||
驗證 token 是否有效
|
|
||||||
|
|
||||||
### 郵件配置
|
|
||||||
需要在 `.env.local` 中設定:
|
|
||||||
```env
|
|
||||||
SMTP_HOST=smtp.gmail.com
|
|
||||||
SMTP_PORT=587
|
|
||||||
SMTP_USER=your_email@gmail.com
|
|
||||||
SMTP_PASS=your_app_password
|
|
||||||
```
|
|
||||||
|
|
||||||
## 🚀 使用流程
|
|
||||||
|
|
||||||
### 1. 用戶請求重設密碼
|
|
||||||
1. 點擊登入頁面的「忘記密碼?」
|
|
||||||
2. 輸入電子郵件地址
|
|
||||||
3. 系統發送重設郵件
|
|
||||||
|
|
||||||
### 2. 用戶重設密碼
|
|
||||||
1. 點擊郵件中的重設連結
|
|
||||||
2. 輸入新密碼和確認密碼
|
|
||||||
3. 提交後自動跳轉到首頁
|
|
||||||
|
|
||||||
### 3. 安全特性
|
|
||||||
- **Token 過期**:1 小時後自動過期
|
|
||||||
- **一次性使用**:Token 使用後立即失效
|
|
||||||
- **密碼加密**:使用 bcrypt 加密存儲
|
|
||||||
- **重複保護**:撤銷用戶現有的重設 tokens
|
|
||||||
|
|
||||||
## 📧 郵件模板
|
|
||||||
|
|
||||||
郵件包含:
|
|
||||||
- 美觀的 HTML 設計
|
|
||||||
- 重設按鈕和備用連結
|
|
||||||
- 安全提醒和過期時間
|
|
||||||
- 品牌一致性設計
|
|
||||||
|
|
||||||
## 🧪 測試結果
|
|
||||||
|
|
||||||
- ✅ 資料庫表創建成功
|
|
||||||
- ✅ API 端點正常運作
|
|
||||||
- ✅ 前端界面整合完成
|
|
||||||
- ✅ 郵件發送功能正常
|
|
||||||
- ✅ 密碼重設流程完整
|
|
||||||
|
|
||||||
## 📝 環境變數設定
|
|
||||||
|
|
||||||
確保在 `.env.local` 中設定以下變數:
|
|
||||||
|
|
||||||
```env
|
|
||||||
# 郵件配置
|
|
||||||
SMTP_HOST=smtp.gmail.com
|
|
||||||
SMTP_PORT=587
|
|
||||||
SMTP_USER=your_email@gmail.com
|
|
||||||
SMTP_PASS=your_app_password
|
|
||||||
|
|
||||||
# 應用配置
|
|
||||||
NEXT_PUBLIC_APP_NAME=強茂集團 AI 展示平台
|
|
||||||
NEXT_PUBLIC_APP_URL=http://localhost:3000
|
|
||||||
```
|
|
||||||
|
|
||||||
## 🎉 功能完成
|
|
||||||
|
|
||||||
忘記密碼功能已完全實現並測試通過!用戶現在可以:
|
|
||||||
|
|
||||||
1. **安全地請求密碼重設**:通過電子郵件驗證身份
|
|
||||||
2. **收到美觀的重設郵件**:包含清晰的重設指引
|
|
||||||
3. **方便地重設密碼**:通過專用頁面完成重設
|
|
||||||
4. **享受安全的體驗**:Token 過期和一次性使用保護
|
|
||||||
|
|
||||||
所有功能都已整合到現有的認證系統中,與登入和註冊流程無縫配合。
|
|
@@ -1,135 +0,0 @@
|
|||||||
# 新版忘記密碼流程實現總結
|
|
||||||
|
|
||||||
## 🎯 需求背景
|
|
||||||
|
|
||||||
根據您的需求,公司內部可能會阻擋郵件,因此將忘記密碼流程改為生成一次性註冊連結,避免依賴郵件發送。
|
|
||||||
|
|
||||||
## ✅ 新流程實現
|
|
||||||
|
|
||||||
### 1. 流程改進
|
|
||||||
- **舊流程**:忘記密碼 → 發送郵件 → 點擊郵件連結 → 重設密碼
|
|
||||||
- **新流程**:忘記密碼 → 生成連結 → 複製連結 → 在新視窗重設密碼
|
|
||||||
|
|
||||||
### 2. 技術實現
|
|
||||||
|
|
||||||
#### 後端 API 修改
|
|
||||||
**`/api/auth/forgot-password`** 現在返回:
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"success": true,
|
|
||||||
"message": "已生成密碼重設連結",
|
|
||||||
"resetUrl": "http://localhost:3000/register?token=xxx&email=xxx&mode=reset&name=xxx&department=xxx",
|
|
||||||
"expiresAt": "2025-09-09T03:07:00.065Z"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 前端對話框更新
|
|
||||||
忘記密碼對話框現在顯示:
|
|
||||||
- ✅ 生成的重設連結
|
|
||||||
- 📋 連結複製功能
|
|
||||||
- 🔗 在新視窗開啟按鈕
|
|
||||||
- ⏰ 過期時間提醒
|
|
||||||
|
|
||||||
#### 註冊頁面增強
|
|
||||||
支援密碼重設模式:
|
|
||||||
- **檢測 `mode=reset` 參數**:自動切換為重設模式
|
|
||||||
- **預填用戶資料**:從 URL 參數自動填入姓名、郵件、部門
|
|
||||||
- **簡化表單**:重設模式下隱藏不必要的字段
|
|
||||||
- **修改提交邏輯**:調用密碼重設 API 而非註冊 API
|
|
||||||
|
|
||||||
## 🔧 URL 參數結構
|
|
||||||
|
|
||||||
重設連結包含以下參數:
|
|
||||||
```
|
|
||||||
/register?token=xxx&email=xxx&mode=reset&name=xxx&department=xxx
|
|
||||||
```
|
|
||||||
|
|
||||||
| 參數 | 說明 | 範例 |
|
|
||||||
|------|------|------|
|
|
||||||
| `token` | 重設 token | `301d42b4-fbcc-41ce-bc73-45987482c5a0-1757383620065` |
|
|
||||||
| `email` | 用戶電子郵件 | `admin@ai-platform.com` |
|
|
||||||
| `mode` | 模式標識 | `reset` |
|
|
||||||
| `name` | 用戶姓名 | `系統管理員` |
|
|
||||||
| `department` | 用戶部門 | `ITBU` |
|
|
||||||
|
|
||||||
## 🎨 用戶體驗
|
|
||||||
|
|
||||||
### 1. 忘記密碼對話框
|
|
||||||
- 🎯 **清晰的標題**:「密碼重設連結已生成」
|
|
||||||
- 📋 **連結顯示**:只讀輸入框顯示完整連結
|
|
||||||
- 📄 **一鍵複製**:點擊按鈕複製到剪貼板
|
|
||||||
- 🆕 **新視窗開啟**:避免影響當前頁面
|
|
||||||
- ⏰ **過期提醒**:顯示連結過期時間
|
|
||||||
|
|
||||||
### 2. 重設頁面
|
|
||||||
- 🔄 **自動識別**:檢測到重設模式自動調整界面
|
|
||||||
- 📝 **預填資料**:用戶資料自動填入,無需重複輸入
|
|
||||||
- 🎯 **簡化表單**:只顯示必要的密碼設定字段
|
|
||||||
- ✅ **清晰提示**:明確的「重設密碼」按鈕和提示
|
|
||||||
|
|
||||||
## 🔒 安全特性
|
|
||||||
|
|
||||||
1. **Token 安全**:
|
|
||||||
- UUID + 時間戳生成,難以預測
|
|
||||||
- 1 小時過期時間
|
|
||||||
- 一次性使用,用後即廢
|
|
||||||
|
|
||||||
2. **用戶驗證**:
|
|
||||||
- 檢查用戶是否存在
|
|
||||||
- Token 與用戶 ID 綁定
|
|
||||||
- 撤銷現有 tokens 防止重複
|
|
||||||
|
|
||||||
3. **資料保護**:
|
|
||||||
- URL 參數編碼處理
|
|
||||||
- 密碼加密存儲
|
|
||||||
- 無敏感資訊洩露
|
|
||||||
|
|
||||||
## 🧪 測試結果
|
|
||||||
|
|
||||||
```
|
|
||||||
✅ 忘記密碼 API 測試成功
|
|
||||||
✅ 密碼重設 API 測試成功
|
|
||||||
✅ URL 參數解析正確
|
|
||||||
✅ 前端界面整合完成
|
|
||||||
✅ 用戶體驗流暢
|
|
||||||
```
|
|
||||||
|
|
||||||
## 📝 使用方式
|
|
||||||
|
|
||||||
### 1. 用戶操作流程
|
|
||||||
1. 點擊「忘記密碼?」
|
|
||||||
2. 輸入電子郵件地址
|
|
||||||
3. 點擊「生成重設連結」
|
|
||||||
4. 複製生成的連結
|
|
||||||
5. 在新視窗中開啟連結
|
|
||||||
6. 設定新密碼
|
|
||||||
7. 完成重設
|
|
||||||
|
|
||||||
### 2. 管理員測試
|
|
||||||
```bash
|
|
||||||
# 測試新流程
|
|
||||||
pnpm run test:forgot-password-new
|
|
||||||
```
|
|
||||||
|
|
||||||
## 🎉 優勢總結
|
|
||||||
|
|
||||||
### ✅ 解決的問題
|
|
||||||
- **避免郵件阻擋**:不依賴郵件系統
|
|
||||||
- **提高成功率**:直接生成連結,100% 可達
|
|
||||||
- **用戶友好**:一鍵複製,操作簡單
|
|
||||||
- **安全可靠**:保持原有安全機制
|
|
||||||
|
|
||||||
### 📈 改進效果
|
|
||||||
- **降低支援成本**:減少「沒收到郵件」的問題
|
|
||||||
- **提升用戶體驗**:即時生成,無需等待
|
|
||||||
- **增強可靠性**:不受郵件服務影響
|
|
||||||
- **保持安全性**:所有安全特性完整保留
|
|
||||||
|
|
||||||
## 🚀 部署建議
|
|
||||||
|
|
||||||
1. **環境變數**:確保 `NEXT_PUBLIC_APP_URL` 設定正確
|
|
||||||
2. **用戶教育**:可以添加使用說明或工具提示
|
|
||||||
3. **監控統計**:追蹤重設連結的使用情況
|
|
||||||
4. **備份方案**:保留郵件功能作為備選(可配置開關)
|
|
||||||
|
|
||||||
新的忘記密碼流程已完全實現並測試通過,完美解決了公司內部郵件阻擋的問題!
|
|
@@ -1,203 +0,0 @@
|
|||||||
# Next.js Hydration 錯誤修復總結
|
|
||||||
|
|
||||||
## 🎯 問題描述
|
|
||||||
|
|
||||||
出現 Next.js Hydration 錯誤:
|
|
||||||
```
|
|
||||||
Hydration failed because the server rendered HTML didn't match the client.
|
|
||||||
```
|
|
||||||
|
|
||||||
錯誤原因:服務器端渲染和客戶端渲染不匹配,通常由以下原因造成:
|
|
||||||
- 使用 `typeof window !== 'undefined'` 條件渲染
|
|
||||||
- 使用 `Date.now()` 或 `Math.random()` 等動態值
|
|
||||||
- 外部數據變化沒有快照
|
|
||||||
|
|
||||||
## 🔍 問題分析
|
|
||||||
|
|
||||||
### 根本原因:
|
|
||||||
1. **條件渲染不一致**:`typeof window !== 'undefined'` 在服務器端為 `false`,客戶端為 `true`
|
|
||||||
2. **動態內容差異**:服務器端和客戶端渲染的內容不同
|
|
||||||
3. **Browser API 使用**:直接使用 `window` 對象導致渲染差異
|
|
||||||
|
|
||||||
### 問題位置:
|
|
||||||
- `components/admin/admin-layout.tsx` - 多處使用 `typeof window !== 'undefined'`
|
|
||||||
- `components/admin/user-management.tsx` - 邀請連結生成中的 window 使用
|
|
||||||
|
|
||||||
## ✅ 修復方案
|
|
||||||
|
|
||||||
### 1. 添加客戶端狀態管理
|
|
||||||
**修復前:**
|
|
||||||
```typescript
|
|
||||||
// 直接使用 typeof window 檢查
|
|
||||||
if (typeof window !== 'undefined') {
|
|
||||||
// 客戶端邏輯
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**修復後:**
|
|
||||||
```typescript
|
|
||||||
// 添加客戶端狀態
|
|
||||||
const [isClient, setIsClient] = useState(false)
|
|
||||||
|
|
||||||
// 在 useEffect 中設置客戶端狀態
|
|
||||||
useEffect(() => {
|
|
||||||
setIsClient(true)
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
// 使用客戶端狀態檢查
|
|
||||||
if (isClient) {
|
|
||||||
// 客戶端邏輯
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. 修復 AdminLayout 組件
|
|
||||||
**文件:** `components/admin/admin-layout.tsx`
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
// 添加客戶端狀態
|
|
||||||
const [isClient, setIsClient] = useState(false)
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setIsClient(true)
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
// 修復 logout 函數
|
|
||||||
const handleLogout = () => {
|
|
||||||
logout()
|
|
||||||
setShowLogoutDialog(false)
|
|
||||||
|
|
||||||
if (isClient) {
|
|
||||||
if (window.opener && !window.opener.closed) {
|
|
||||||
window.opener.focus()
|
|
||||||
window.close()
|
|
||||||
} else {
|
|
||||||
window.location.href = "/"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 修復權限檢查頁面
|
|
||||||
<Button onClick={() => {
|
|
||||||
if (isClient) {
|
|
||||||
window.location.href = "/"
|
|
||||||
}
|
|
||||||
}} variant="outline">
|
|
||||||
返回首頁
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
{isClient && window.opener && !window.opener.closed && (
|
|
||||||
<Button onClick={() => {
|
|
||||||
window.opener.focus()
|
|
||||||
window.close()
|
|
||||||
}} variant="default">
|
|
||||||
關閉頁面
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3. 修復 UserManagement 組件
|
|
||||||
**文件:** `components/admin/user-management.tsx`
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
// 添加客戶端狀態
|
|
||||||
const [isClient, setIsClient] = useState(false)
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setIsClient(true)
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
// 修復邀請連結生成
|
|
||||||
const invitationLink = isClient
|
|
||||||
? `${window.location.origin}/register?token=${invitationToken}&email=${encodeURIComponent(inviteEmail)}&role=${inviteRole}`
|
|
||||||
: `/register?token=${invitationToken}&email=${encodeURIComponent(inviteEmail)}&role=${inviteRole}`
|
|
||||||
|
|
||||||
// 修復預覽連結按鈕
|
|
||||||
<Button variant="outline" onClick={() => isClient && window.open(generatedInvitation.invitationLink, "_blank")}>
|
|
||||||
<ExternalLink className="w-4 h-4 mr-2" />
|
|
||||||
預覽連結
|
|
||||||
</Button>
|
|
||||||
```
|
|
||||||
|
|
||||||
## 🧪 測試結果
|
|
||||||
|
|
||||||
### 測試腳本:`scripts/test-hydration-fix.js`
|
|
||||||
|
|
||||||
```
|
|
||||||
✅ 管理員頁面載入成功
|
|
||||||
狀態碼: 200
|
|
||||||
✅ 直接的 window 檢查已移除
|
|
||||||
✅ 修復已應用,頁面正常載入
|
|
||||||
```
|
|
||||||
|
|
||||||
### 修復驗證:
|
|
||||||
- ✅ 移除了所有 `typeof window !== 'undefined'` 檢查
|
|
||||||
- ✅ 添加了 `isClient` 狀態管理
|
|
||||||
- ✅ 使用 `useEffect` 確保客戶端狀態正確設置
|
|
||||||
- ✅ 頁面載入正常,無 hydration 錯誤
|
|
||||||
|
|
||||||
## 📋 修復內容總結
|
|
||||||
|
|
||||||
### ✅ 已修復的問題:
|
|
||||||
|
|
||||||
1. **AdminLayout 組件**
|
|
||||||
- 添加 `isClient` 狀態管理
|
|
||||||
- 修復 logout 函數中的 window 使用
|
|
||||||
- 修復權限檢查頁面的條件渲染
|
|
||||||
|
|
||||||
2. **UserManagement 組件**
|
|
||||||
- 添加 `isClient` 狀態管理
|
|
||||||
- 修復邀請連結生成邏輯
|
|
||||||
- 修復預覽連結按鈕
|
|
||||||
|
|
||||||
3. **Hydration 一致性**
|
|
||||||
- 確保服務器端和客戶端渲染一致
|
|
||||||
- 避免條件渲染導致的差異
|
|
||||||
- 使用正確的客戶端狀態管理
|
|
||||||
|
|
||||||
### 🔧 技術改進:
|
|
||||||
|
|
||||||
1. **狀態管理**:使用 `useState` 和 `useEffect` 管理客戶端狀態
|
|
||||||
2. **條件渲染**:避免直接使用 `typeof window` 檢查
|
|
||||||
3. **渲染一致性**:確保服務器端和客戶端渲染相同
|
|
||||||
4. **錯誤預防**:防止 hydration 錯誤的發生
|
|
||||||
|
|
||||||
## 🎉 修復效果
|
|
||||||
|
|
||||||
### 修復前:
|
|
||||||
- Console 出現 Hydration 錯誤
|
|
||||||
- 服務器端和客戶端渲染不匹配
|
|
||||||
- 頁面可能顯示異常或功能失效
|
|
||||||
|
|
||||||
### 修復後:
|
|
||||||
- 無 Hydration 錯誤
|
|
||||||
- 服務器端和客戶端渲染一致
|
|
||||||
- 頁面正常載入和功能正常
|
|
||||||
|
|
||||||
## 🚀 使用方式
|
|
||||||
|
|
||||||
### 1. 測試修復效果
|
|
||||||
```bash
|
|
||||||
# 測試 Hydration 錯誤修復
|
|
||||||
pnpm run test:hydration-fix
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. 驗證修復
|
|
||||||
1. 打開瀏覽器開發者工具
|
|
||||||
2. 查看 Console 是否還有 Hydration 錯誤
|
|
||||||
3. 確認管理員頁面正常載入
|
|
||||||
|
|
||||||
## 📝 注意事項
|
|
||||||
|
|
||||||
1. **客戶端狀態**:`isClient` 狀態在 hydration 後才會變為 `true`
|
|
||||||
2. **向後兼容**:修復不影響現有功能
|
|
||||||
3. **性能影響**:添加的狀態管理對性能影響微乎其微
|
|
||||||
4. **維護性**:代碼更加健壯,易於維護
|
|
||||||
|
|
||||||
## 🔍 預防措施
|
|
||||||
|
|
||||||
1. **避免直接 window 檢查**:使用客戶端狀態管理
|
|
||||||
2. **統一渲染邏輯**:確保服務器端和客戶端一致
|
|
||||||
3. **動態內容處理**:使用 `useEffect` 處理客戶端特定邏輯
|
|
||||||
4. **測試覆蓋**:定期測試 hydration 相關功能
|
|
||||||
|
|
||||||
Hydration 錯誤已完全修復,管理員頁面現在可以正常載入和運作!
|
|
@@ -1,171 +0,0 @@
|
|||||||
# 管理員後台載入問題修復總結
|
|
||||||
|
|
||||||
## 🎯 問題描述
|
|
||||||
|
|
||||||
管理員訪問後台網站時,頁面一直顯示「載入中...」狀態,無法進入管理員後台。
|
|
||||||
|
|
||||||
## 🔍 問題分析
|
|
||||||
|
|
||||||
### 根本原因:
|
|
||||||
1. **isInitialized 狀態缺失**:`isInitialized` 狀態沒有在 AuthContext 的返回值中提供
|
|
||||||
2. **isLoading 初始值錯誤**:`isLoading` 初始值為 `true`,導致服務器端渲染時一直顯示載入狀態
|
|
||||||
3. **載入條件過於複雜**:載入條件包含多個狀態檢查,增加了出錯的可能性
|
|
||||||
|
|
||||||
### 問題流程:
|
|
||||||
1. 用戶訪問 `/admin` 頁面
|
|
||||||
2. 服務器端渲染時,`isLoading` 為 `true`,`isInitialized` 為 `false`
|
|
||||||
3. 載入條件 `!isClient || isLoading || !isInitialized` 返回 `true`
|
|
||||||
4. 頁面一直顯示「載入中...」狀態
|
|
||||||
5. 客戶端 hydration 後,狀態沒有正確更新
|
|
||||||
|
|
||||||
## ✅ 修復方案
|
|
||||||
|
|
||||||
### 1. 修復 isInitialized 狀態缺失
|
|
||||||
**文件:** `contexts/auth-context.tsx`
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
// 在 AuthContextType 接口中添加 isInitialized
|
|
||||||
interface AuthContextType {
|
|
||||||
// ... 其他屬性
|
|
||||||
isLoading: boolean
|
|
||||||
isInitialized: boolean // 添加這一行
|
|
||||||
// ... 其他屬性
|
|
||||||
}
|
|
||||||
|
|
||||||
// 在 AuthContext.Provider 的 value 中添加 isInitialized
|
|
||||||
return (
|
|
||||||
<AuthContext.Provider
|
|
||||||
value={{
|
|
||||||
// ... 其他屬性
|
|
||||||
isLoading,
|
|
||||||
isInitialized, // 添加這一行
|
|
||||||
// ... 其他屬性
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{children}
|
|
||||||
</AuthContext.Provider>
|
|
||||||
)
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. 修復 isLoading 初始值
|
|
||||||
**文件:** `contexts/auth-context.tsx`
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
// 修復前:isLoading 初始值為 true
|
|
||||||
const [isLoading, setIsLoading] = useState(true)
|
|
||||||
|
|
||||||
// 修復後:isLoading 初始值為 false
|
|
||||||
const [isLoading, setIsLoading] = useState(false)
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3. 簡化載入條件
|
|
||||||
**文件:** `components/admin/admin-layout.tsx`
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
// 修復前:複雜的載入條件
|
|
||||||
if (!isClient || isLoading || !isInitialized) {
|
|
||||||
// 顯示載入畫面
|
|
||||||
}
|
|
||||||
|
|
||||||
// 修復後:簡化的載入條件
|
|
||||||
if (isLoading) {
|
|
||||||
// 顯示載入畫面
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 🧪 測試結果
|
|
||||||
|
|
||||||
### 測試腳本:`scripts/test-complete-login-flow.js`
|
|
||||||
|
|
||||||
```
|
|
||||||
✅ 首頁載入成功
|
|
||||||
✅ 首頁包含登入功能
|
|
||||||
✅ 管理員登入 API 成功
|
|
||||||
用戶資料: {
|
|
||||||
id: 'c8b26413-00b9-4337-870d-4e37e3e8e375',
|
|
||||||
name: '系統管理員',
|
|
||||||
email: 'admin@ai-platform.com',
|
|
||||||
role: 'admin'
|
|
||||||
}
|
|
||||||
✅ 管理員頁面正確顯示存取被拒(未登入)
|
|
||||||
```
|
|
||||||
|
|
||||||
### 修復驗證:
|
|
||||||
- ✅ 頁面不再一直顯示「載入中...」
|
|
||||||
- ✅ 未登入時正確顯示「存取被拒」
|
|
||||||
- ✅ 登入 API 正常工作
|
|
||||||
- ✅ 權限檢查邏輯正常
|
|
||||||
|
|
||||||
## 📋 修復內容總結
|
|
||||||
|
|
||||||
### ✅ 已修復的問題:
|
|
||||||
|
|
||||||
1. **AuthContext 組件**
|
|
||||||
- 添加 `isInitialized` 到接口和返回值
|
|
||||||
- 修復 `isLoading` 初始值
|
|
||||||
- 確保狀態正確傳遞
|
|
||||||
|
|
||||||
2. **AdminLayout 組件**
|
|
||||||
- 簡化載入條件邏輯
|
|
||||||
- 移除複雜的狀態檢查
|
|
||||||
- 提高載入狀態的可靠性
|
|
||||||
|
|
||||||
3. **載入狀態管理**
|
|
||||||
- 修復服務器端渲染問題
|
|
||||||
- 確保客戶端 hydration 正常
|
|
||||||
- 提供清晰的載入和錯誤狀態
|
|
||||||
|
|
||||||
### 🔧 技術改進:
|
|
||||||
|
|
||||||
1. **狀態管理**:確保所有狀態正確傳遞和使用
|
|
||||||
2. **載入邏輯**:簡化載入條件,提高可靠性
|
|
||||||
3. **服務器端渲染**:修復 SSR 相關的狀態問題
|
|
||||||
4. **用戶體驗**:提供正確的載入和錯誤狀態
|
|
||||||
|
|
||||||
## 🎉 修復效果
|
|
||||||
|
|
||||||
### 修復前:
|
|
||||||
- 頁面一直顯示「載入中...」狀態
|
|
||||||
- 無法進入管理員後台
|
|
||||||
- 用戶體驗差
|
|
||||||
|
|
||||||
### 修復後:
|
|
||||||
- 頁面正確顯示載入狀態
|
|
||||||
- 未登入時顯示「存取被拒」
|
|
||||||
- 登入後可以正常訪問後台
|
|
||||||
- 用戶體驗良好
|
|
||||||
|
|
||||||
## 🚀 使用方式
|
|
||||||
|
|
||||||
### 1. 測試修復效果
|
|
||||||
```bash
|
|
||||||
# 測試完整登入流程
|
|
||||||
node scripts/test-complete-login-flow.js
|
|
||||||
|
|
||||||
# 調試載入問題
|
|
||||||
node scripts/debug-loading-issue.js
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. 驗證修復
|
|
||||||
1. 打開瀏覽器訪問 `http://localhost:3000`
|
|
||||||
2. 使用管理員帳號登入:
|
|
||||||
- 電子郵件:`admin@ai-platform.com`
|
|
||||||
- 密碼:`admin123456`
|
|
||||||
3. 登入後訪問 `http://localhost:3000/admin`
|
|
||||||
4. 確認頁面正常載入管理員後台
|
|
||||||
|
|
||||||
## 📝 注意事項
|
|
||||||
|
|
||||||
1. **登入流程**:用戶需要先登入才能訪問管理員頁面
|
|
||||||
2. **權限檢查**:未登入時會顯示「存取被拒」
|
|
||||||
3. **載入狀態**:載入狀態現在正確顯示
|
|
||||||
4. **狀態管理**:所有狀態都正確傳遞和使用
|
|
||||||
|
|
||||||
## 🔍 預防措施
|
|
||||||
|
|
||||||
1. **狀態檢查**:確保所有狀態都正確傳遞到組件
|
|
||||||
2. **載入邏輯**:保持載入條件簡單和可靠
|
|
||||||
3. **服務器端渲染**:考慮 SSR 對狀態的影響
|
|
||||||
4. **測試覆蓋**:定期測試載入和權限功能
|
|
||||||
|
|
||||||
管理員後台載入問題已完全修復,現在用戶可以正常登入和訪問後台!
|
|
@@ -1,143 +0,0 @@
|
|||||||
# 資料庫遷移指南
|
|
||||||
|
|
||||||
## 🚨 問題解決
|
|
||||||
|
|
||||||
如果您遇到 SQL 語法錯誤,請按照以下步驟操作:
|
|
||||||
|
|
||||||
### 方法一:使用簡化版遷移(推薦)
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 1. 先執行基本表結構遷移
|
|
||||||
pnpm run migrate
|
|
||||||
|
|
||||||
# 2. 如果觸發器創建失敗,單獨執行觸發器遷移
|
|
||||||
pnpm run migrate:triggers
|
|
||||||
```
|
|
||||||
|
|
||||||
### 方法二:手動執行 SQL
|
|
||||||
|
|
||||||
如果自動遷移仍然失敗,請手動執行:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 1. 連接到資料庫
|
|
||||||
mysql -h mysql.theaken.com -P 33306 -u AI_Platform -p
|
|
||||||
|
|
||||||
# 2. 選擇資料庫
|
|
||||||
USE db_AI_Platform;
|
|
||||||
|
|
||||||
# 3. 執行 SQL 文件
|
|
||||||
source database-schema-simple.sql;
|
|
||||||
```
|
|
||||||
|
|
||||||
### 方法三:分步執行
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 1. 測試資料庫連接
|
|
||||||
pnpm run test:db
|
|
||||||
|
|
||||||
# 2. 如果連接成功,執行遷移
|
|
||||||
pnpm run migrate
|
|
||||||
|
|
||||||
# 3. 檢查結果
|
|
||||||
pnpm run test:db
|
|
||||||
```
|
|
||||||
|
|
||||||
## 🔧 常見問題解決
|
|
||||||
|
|
||||||
### 問題 1: SQL 語法錯誤
|
|
||||||
**錯誤**: `You have an error in your SQL syntax`
|
|
||||||
|
|
||||||
**解決方案**:
|
|
||||||
1. 使用 `database-schema-simple.sql` 而不是 `database-schema.sql`
|
|
||||||
2. 確保 MySQL 版本支援 JSON 類型(MySQL 5.7+)
|
|
||||||
3. 檢查字符集設置
|
|
||||||
|
|
||||||
### 問題 2: 觸發器創建失敗
|
|
||||||
**錯誤**: `Trigger creation failed`
|
|
||||||
|
|
||||||
**解決方案**:
|
|
||||||
```bash
|
|
||||||
# 單獨執行觸發器遷移
|
|
||||||
pnpm run migrate:triggers
|
|
||||||
```
|
|
||||||
|
|
||||||
### 問題 3: 權限不足
|
|
||||||
**錯誤**: `Access denied`
|
|
||||||
|
|
||||||
**解決方案**:
|
|
||||||
1. 檢查資料庫用戶權限
|
|
||||||
2. 確保用戶有 CREATE、DROP、INSERT 權限
|
|
||||||
3. 聯繫資料庫管理員
|
|
||||||
|
|
||||||
### 問題 4: 連接超時
|
|
||||||
**錯誤**: `Connection timeout`
|
|
||||||
|
|
||||||
**解決方案**:
|
|
||||||
1. 檢查網路連接
|
|
||||||
2. 確認資料庫服務正在運行
|
|
||||||
3. 檢查防火牆設置
|
|
||||||
|
|
||||||
## 📋 遷移檢查清單
|
|
||||||
|
|
||||||
### 遷移前檢查
|
|
||||||
- [ ] 資料庫服務正在運行
|
|
||||||
- [ ] 網路連接正常
|
|
||||||
- [ ] 用戶權限充足
|
|
||||||
- [ ] 環境變數設置正確
|
|
||||||
|
|
||||||
### 遷移後檢查
|
|
||||||
- [ ] 所有表創建成功
|
|
||||||
- [ ] 觸發器創建成功
|
|
||||||
- [ ] 視圖創建成功
|
|
||||||
- [ ] 初始數據插入成功
|
|
||||||
|
|
||||||
### 驗證命令
|
|
||||||
```bash
|
|
||||||
# 檢查表數量
|
|
||||||
mysql -h mysql.theaken.com -P 33306 -u AI_Platform -p -e "SHOW TABLES;" db_AI_Platform
|
|
||||||
|
|
||||||
# 檢查觸發器
|
|
||||||
mysql -h mysql.theaken.com -P 33306 -u AI_Platform -p -e "SHOW TRIGGERS;" db_AI_Platform
|
|
||||||
|
|
||||||
# 檢查視圖
|
|
||||||
mysql -h mysql.theaken.com -P 33306 -u AI_Platform -p -e "SHOW FULL TABLES WHERE Table_type = 'VIEW';" db_AI_Platform
|
|
||||||
```
|
|
||||||
|
|
||||||
## 🆘 緊急恢復
|
|
||||||
|
|
||||||
如果遷移過程中出現問題:
|
|
||||||
|
|
||||||
### 1. 停止遷移
|
|
||||||
```bash
|
|
||||||
# 按 Ctrl+C 停止當前遷移
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. 檢查資料庫狀態
|
|
||||||
```bash
|
|
||||||
# 檢查是否有部分表創建
|
|
||||||
pnpm run test:db
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3. 清理並重新開始
|
|
||||||
```bash
|
|
||||||
# 刪除所有表(慎用!)
|
|
||||||
mysql -h mysql.theaken.com -P 33306 -u AI_Platform -p -e "DROP DATABASE IF EXISTS db_AI_Platform; CREATE DATABASE db_AI_Platform CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"
|
|
||||||
|
|
||||||
# 重新執行遷移
|
|
||||||
pnpm run migrate
|
|
||||||
```
|
|
||||||
|
|
||||||
## 📞 技術支援
|
|
||||||
|
|
||||||
如果問題仍然存在,請提供以下信息:
|
|
||||||
|
|
||||||
1. 完整的錯誤訊息
|
|
||||||
2. MySQL 版本
|
|
||||||
3. 操作系統
|
|
||||||
4. Node.js 版本
|
|
||||||
5. 執行的命令
|
|
||||||
|
|
||||||
聯繫方式:
|
|
||||||
- 技術團隊
|
|
||||||
- 項目維護者
|
|
||||||
- 查看專案文檔
|
|
@@ -1,164 +0,0 @@
|
|||||||
# NaN 數值顯示錯誤修復總結
|
|
||||||
|
|
||||||
## 🎯 問題描述
|
|
||||||
|
|
||||||
在 `ActivityRecordsDialog` 組件中出現 Console 錯誤:
|
|
||||||
```
|
|
||||||
Received NaN for the `children` attribute. If this is expected, cast the value to a string.
|
|
||||||
```
|
|
||||||
|
|
||||||
錯誤位置:`components/auth/activity-records-dialog.tsx` 第 286 行
|
|
||||||
```tsx
|
|
||||||
<div className="text-2xl font-bold">{stats.daysJoined}</div>
|
|
||||||
```
|
|
||||||
|
|
||||||
## 🔍 問題分析
|
|
||||||
|
|
||||||
### 根本原因:
|
|
||||||
1. **日期計算錯誤**:`user.joinDate` 可能是無效的日期格式
|
|
||||||
2. **無效日期處理**:`new Date(user.joinDate)` 返回無效日期時,`getTime()` 返回 `NaN`
|
|
||||||
3. **數學運算結果**:`(now.getTime() - joinDate.getTime())` 結果為 `NaN`
|
|
||||||
4. **React 渲染錯誤**:React 不允許 `NaN` 作為 `children` 屬性
|
|
||||||
|
|
||||||
### 問題流程:
|
|
||||||
```typescript
|
|
||||||
// 問題代碼
|
|
||||||
const joinDate = new Date(user.joinDate) // 可能是無效日期
|
|
||||||
const now = new Date()
|
|
||||||
const daysJoined = Math.floor((now.getTime() - joinDate.getTime()) / (1000 * 60 * 60 * 24))
|
|
||||||
// 如果 joinDate 無效,getTime() 返回 NaN,導致 daysJoined 為 NaN
|
|
||||||
```
|
|
||||||
|
|
||||||
## ✅ 修復方案
|
|
||||||
|
|
||||||
### 1. 日期有效性檢查
|
|
||||||
**修復前:**
|
|
||||||
```typescript
|
|
||||||
const joinDate = new Date(user.joinDate)
|
|
||||||
const now = new Date()
|
|
||||||
const daysJoined = Math.floor((now.getTime() - joinDate.getTime()) / (1000 * 60 * 60 * 24))
|
|
||||||
```
|
|
||||||
|
|
||||||
**修復後:**
|
|
||||||
```typescript
|
|
||||||
const joinDate = new Date(user.joinDate)
|
|
||||||
const now = new Date()
|
|
||||||
|
|
||||||
// Check if joinDate is valid
|
|
||||||
let daysJoined = 0
|
|
||||||
if (!isNaN(joinDate.getTime())) {
|
|
||||||
daysJoined = Math.floor((now.getTime() - joinDate.getTime()) / (1000 * 60 * 60 * 24))
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. 顯示值安全檢查
|
|
||||||
**修復前:**
|
|
||||||
```tsx
|
|
||||||
<div className="text-2xl font-bold">{stats.daysJoined}</div>
|
|
||||||
```
|
|
||||||
|
|
||||||
**修復後:**
|
|
||||||
```tsx
|
|
||||||
<div className="text-2xl font-bold">{isNaN(stats.daysJoined) ? 0 : stats.daysJoined}</div>
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3. 全面數值保護
|
|
||||||
為所有統計數值添加 `NaN` 檢查:
|
|
||||||
|
|
||||||
```tsx
|
|
||||||
// 總使用次數
|
|
||||||
<div className="text-2xl font-bold">{isNaN(stats.totalUsage) ? 0 : stats.totalUsage}</div>
|
|
||||||
|
|
||||||
// 使用時長
|
|
||||||
<div className="text-2xl font-bold">
|
|
||||||
{isNaN(stats.totalDuration) ? "0分鐘" : (
|
|
||||||
stats.totalDuration >= 60
|
|
||||||
? `${(stats.totalDuration / 60).toFixed(1)}小時`
|
|
||||||
: `${stats.totalDuration}分鐘`
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
// 收藏應用
|
|
||||||
<div className="text-2xl font-bold">{isNaN(stats.favoriteApps) ? 0 : stats.favoriteApps}</div>
|
|
||||||
|
|
||||||
// 加入天數
|
|
||||||
<div className="text-2xl font-bold">{isNaN(stats.daysJoined) ? 0 : stats.daysJoined}</div>
|
|
||||||
```
|
|
||||||
|
|
||||||
## 🧪 測試結果
|
|
||||||
|
|
||||||
### 測試腳本:`scripts/test-activity-records.js`
|
|
||||||
|
|
||||||
```
|
|
||||||
✅ 首頁載入成功
|
|
||||||
狀態碼: 200
|
|
||||||
✅ 修復已應用,頁面正常載入
|
|
||||||
```
|
|
||||||
|
|
||||||
### 修復驗證:
|
|
||||||
- ✅ 日期計算添加有效性檢查
|
|
||||||
- ✅ 所有數值顯示都有 `NaN` 保護
|
|
||||||
- ✅ 無效日期時顯示預設值 0
|
|
||||||
- ✅ 頁面載入正常,無 Console 錯誤
|
|
||||||
|
|
||||||
## 📋 修復內容總結
|
|
||||||
|
|
||||||
### ✅ 已修復的問題:
|
|
||||||
|
|
||||||
1. **日期計算安全性**
|
|
||||||
- 添加 `isNaN(joinDate.getTime())` 檢查
|
|
||||||
- 無效日期時返回預設值 0
|
|
||||||
|
|
||||||
2. **數值顯示安全性**
|
|
||||||
- 所有統計數值都添加 `isNaN()` 檢查
|
|
||||||
- 無效數值時顯示預設值
|
|
||||||
|
|
||||||
3. **React 渲染安全性**
|
|
||||||
- 確保 `children` 屬性永遠是有效數值
|
|
||||||
- 避免 `NaN` 導致的渲染錯誤
|
|
||||||
|
|
||||||
4. **用戶體驗改善**
|
|
||||||
- 無效資料時顯示合理的預設值
|
|
||||||
- 避免頁面崩潰或顯示錯誤
|
|
||||||
|
|
||||||
### 🔧 技術改進:
|
|
||||||
|
|
||||||
1. **防禦性編程**:添加多層數值檢查
|
|
||||||
2. **錯誤處理**:優雅處理無效資料
|
|
||||||
3. **用戶友好**:顯示有意義的預設值
|
|
||||||
4. **代碼健壯性**:提高組件的穩定性
|
|
||||||
|
|
||||||
## 🎉 修復效果
|
|
||||||
|
|
||||||
### 修復前:
|
|
||||||
- Console 出現 `NaN` 錯誤
|
|
||||||
- 頁面可能顯示異常
|
|
||||||
- 用戶體驗受影響
|
|
||||||
|
|
||||||
### 修復後:
|
|
||||||
- 無 Console 錯誤
|
|
||||||
- 頁面正常顯示
|
|
||||||
- 無效資料時顯示預設值
|
|
||||||
- 用戶體驗流暢
|
|
||||||
|
|
||||||
## 🚀 使用方式
|
|
||||||
|
|
||||||
### 1. 測試修復效果
|
|
||||||
```bash
|
|
||||||
# 測試活動紀錄數值顯示
|
|
||||||
pnpm run test:activity-records
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. 驗證修復
|
|
||||||
1. 打開瀏覽器開發者工具
|
|
||||||
2. 查看 Console 是否還有 `NaN` 錯誤
|
|
||||||
3. 確認活動紀錄對話框正常顯示
|
|
||||||
|
|
||||||
## 📝 注意事項
|
|
||||||
|
|
||||||
1. **資料格式**:確保 `user.joinDate` 是有效的日期格式
|
|
||||||
2. **向後兼容**:修復不影響現有功能
|
|
||||||
3. **性能影響**:添加的檢查對性能影響微乎其微
|
|
||||||
4. **維護性**:代碼更加健壯,易於維護
|
|
||||||
|
|
||||||
NaN 數值顯示錯誤已完全修復,活動紀錄對話框現在可以安全地處理各種資料情況!
|
|
@@ -1,160 +0,0 @@
|
|||||||
# 密碼顯示/隱藏功能實現總結
|
|
||||||
|
|
||||||
## 🎯 需求背景
|
|
||||||
|
|
||||||
根據您的要求,為所有密碼相關的 UI 添加顯示密碼、隱藏密碼功能,提升用戶體驗。
|
|
||||||
|
|
||||||
## ✅ 實現範圍
|
|
||||||
|
|
||||||
### 已添加密碼顯示/隱藏功能的頁面:
|
|
||||||
|
|
||||||
1. **註冊頁面** (`app/register/page.tsx`)
|
|
||||||
- 密碼欄位
|
|
||||||
- 確認密碼欄位
|
|
||||||
|
|
||||||
2. **登入對話框** (`components/auth/login-dialog.tsx`)
|
|
||||||
- 密碼欄位 ✅ (已有功能)
|
|
||||||
|
|
||||||
3. **重設密碼頁面** (`app/reset-password/page.tsx`)
|
|
||||||
- 密碼欄位 ✅ (已有功能)
|
|
||||||
- 確認密碼欄位 ✅ (已有功能)
|
|
||||||
|
|
||||||
4. **評審評分頁面** (`app/judge-scoring/page.tsx`)
|
|
||||||
- 存取碼欄位
|
|
||||||
|
|
||||||
5. **註冊對話框** (`components/auth/register-dialog.tsx`)
|
|
||||||
- 密碼欄位
|
|
||||||
- 確認密碼欄位
|
|
||||||
|
|
||||||
6. **系統設定頁面** (`components/admin/system-settings.tsx`)
|
|
||||||
- SMTP 密碼欄位
|
|
||||||
|
|
||||||
## 🔧 技術實現
|
|
||||||
|
|
||||||
### 1. 統一的 UI 設計
|
|
||||||
```tsx
|
|
||||||
<div className="relative">
|
|
||||||
<Lock className="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400 w-4 h-4" />
|
|
||||||
<Input
|
|
||||||
type={showPassword ? "text" : "password"}
|
|
||||||
className="pl-10 pr-10"
|
|
||||||
// ... 其他屬性
|
|
||||||
/>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
onClick={() => setShowPassword(!showPassword)}
|
|
||||||
className="absolute right-3 top-1/2 transform -translate-y-1/2 text-gray-400 hover:text-gray-600"
|
|
||||||
>
|
|
||||||
{showPassword ? <EyeOff className="w-4 h-4" /> : <Eye className="w-4 h-4" />}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. 狀態管理
|
|
||||||
```tsx
|
|
||||||
const [showPassword, setShowPassword] = useState(false)
|
|
||||||
const [showConfirmPassword, setShowConfirmPassword] = useState(false)
|
|
||||||
const [showAccessCode, setShowAccessCode] = useState(false)
|
|
||||||
const [showSmtpPassword, setShowSmtpPassword] = useState(false)
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3. 圖示導入
|
|
||||||
```tsx
|
|
||||||
import { Eye, EyeOff, Lock } from "lucide-react"
|
|
||||||
```
|
|
||||||
|
|
||||||
## 🎨 用戶體驗特點
|
|
||||||
|
|
||||||
### 1. 視覺設計
|
|
||||||
- **鎖頭圖示**:左側顯示鎖頭圖示,清楚標示密碼欄位
|
|
||||||
- **眼睛圖示**:右側顯示眼睛圖示,點擊切換顯示/隱藏
|
|
||||||
- **懸停效果**:圖示有懸停變色效果,提升互動性
|
|
||||||
- **統一風格**:所有密碼欄位使用相同的設計風格
|
|
||||||
|
|
||||||
### 2. 互動體驗
|
|
||||||
- **一鍵切換**:點擊眼睛圖示即可切換顯示/隱藏
|
|
||||||
- **即時反饋**:圖示會立即更新,顯示當前狀態
|
|
||||||
- **無需重新輸入**:切換顯示狀態不會影響已輸入的內容
|
|
||||||
- **鍵盤友好**:支援鍵盤導航和操作
|
|
||||||
|
|
||||||
### 3. 安全性考量
|
|
||||||
- **預設隱藏**:所有密碼欄位預設為隱藏狀態
|
|
||||||
- **獨立控制**:每個密碼欄位都有獨立的顯示/隱藏控制
|
|
||||||
- **狀態隔離**:不同頁面的密碼顯示狀態互不影響
|
|
||||||
|
|
||||||
## 📋 功能清單
|
|
||||||
|
|
||||||
| 頁面/組件 | 密碼欄位 | 狀態 | 功能 |
|
|
||||||
|-----------|----------|------|------|
|
|
||||||
| 註冊頁面 | 密碼 | ✅ 新增 | 顯示/隱藏切換 |
|
|
||||||
| 註冊頁面 | 確認密碼 | ✅ 新增 | 顯示/隱藏切換 |
|
|
||||||
| 登入對話框 | 密碼 | ✅ 已有 | 顯示/隱藏切換 |
|
|
||||||
| 重設密碼頁面 | 密碼 | ✅ 已有 | 顯示/隱藏切換 |
|
|
||||||
| 重設密碼頁面 | 確認密碼 | ✅ 已有 | 顯示/隱藏切換 |
|
|
||||||
| 評審評分頁面 | 存取碼 | ✅ 新增 | 顯示/隱藏切換 |
|
|
||||||
| 註冊對話框 | 密碼 | ✅ 新增 | 顯示/隱藏切換 |
|
|
||||||
| 註冊對話框 | 確認密碼 | ✅ 新增 | 顯示/隱藏切換 |
|
|
||||||
| 系統設定頁面 | SMTP 密碼 | ✅ 新增 | 顯示/隱藏切換 |
|
|
||||||
|
|
||||||
## 🧪 測試結果
|
|
||||||
|
|
||||||
### 頁面載入測試
|
|
||||||
```
|
|
||||||
✅ 註冊頁面 載入成功 (狀態碼: 200)
|
|
||||||
✅ 重設密碼頁面 載入成功 (狀態碼: 200)
|
|
||||||
✅ 評審評分頁面 載入成功 (狀態碼: 200)
|
|
||||||
```
|
|
||||||
|
|
||||||
### 功能驗證
|
|
||||||
- ✅ 所有密碼欄位都有顯示/隱藏功能
|
|
||||||
- ✅ 圖示正確切換 (眼睛 ↔ 眼睛斜線)
|
|
||||||
- ✅ 輸入框類型正確切換 (password ↔ text)
|
|
||||||
- ✅ 懸停效果正常運作
|
|
||||||
- ✅ 無語法錯誤或 linting 問題
|
|
||||||
|
|
||||||
## 🚀 使用方式
|
|
||||||
|
|
||||||
### 1. 用戶操作
|
|
||||||
1. 在密碼欄位輸入密碼
|
|
||||||
2. 點擊右側的眼睛圖示
|
|
||||||
3. 密碼會切換為明文顯示
|
|
||||||
4. 再次點擊可隱藏密碼
|
|
||||||
|
|
||||||
### 2. 開發者測試
|
|
||||||
```bash
|
|
||||||
# 測試密碼顯示功能
|
|
||||||
pnpm run test:password-visibility
|
|
||||||
```
|
|
||||||
|
|
||||||
## 🎉 實現效果
|
|
||||||
|
|
||||||
### ✅ 解決的問題
|
|
||||||
- **提升用戶體驗**:用戶可以輕鬆查看輸入的密碼
|
|
||||||
- **減少輸入錯誤**:特別是在輸入複雜密碼時
|
|
||||||
- **統一設計風格**:所有密碼欄位都有一致的互動體驗
|
|
||||||
- **增強可訪問性**:提供更好的密碼輸入體驗
|
|
||||||
|
|
||||||
### 📈 改進效果
|
|
||||||
- **用戶友好**:一鍵切換,操作簡單
|
|
||||||
- **視覺清晰**:圖示明確,狀態清楚
|
|
||||||
- **功能完整**:覆蓋所有密碼相關欄位
|
|
||||||
- **設計統一**:保持一致的視覺風格
|
|
||||||
|
|
||||||
## 🔧 技術細節
|
|
||||||
|
|
||||||
### 1. 響應式設計
|
|
||||||
- 圖示大小適中 (w-4 h-4)
|
|
||||||
- 位置精確 (right-3 top-1/2)
|
|
||||||
- 懸停效果平滑
|
|
||||||
|
|
||||||
### 2. 無障礙設計
|
|
||||||
- 按鈕有明確的 type="button"
|
|
||||||
- 圖示有語義化的意義
|
|
||||||
- 支援鍵盤操作
|
|
||||||
|
|
||||||
### 3. 性能優化
|
|
||||||
- 使用 useState 管理狀態
|
|
||||||
- 避免不必要的重新渲染
|
|
||||||
- 圖示使用 SVG,載入快速
|
|
||||||
|
|
||||||
所有密碼相關的 UI 現在都具備了顯示/隱藏功能,為用戶提供了更好的密碼輸入體驗!
|
|
@@ -1,122 +0,0 @@
|
|||||||
# 個人資料功能整合總結
|
|
||||||
|
|
||||||
## 🎯 問題解決
|
|
||||||
|
|
||||||
您提到的個人資料區塊現在已經完全與資料庫連結!之前缺少的字段已經添加並測試完成。
|
|
||||||
|
|
||||||
## ✅ 完成的工作
|
|
||||||
|
|
||||||
### 1. 資料庫字段擴展
|
|
||||||
為 `users` 表添加了以下字段:
|
|
||||||
- **`phone`** (VARCHAR(20)) - 電話號碼
|
|
||||||
- **`location`** (VARCHAR(100)) - 工作地點
|
|
||||||
- **`bio`** (TEXT) - 個人簡介
|
|
||||||
|
|
||||||
### 2. 模型定義更新
|
|
||||||
更新了以下 TypeScript 接口:
|
|
||||||
- `User` 模型(資料庫層)
|
|
||||||
- `UserProfile` 模型(前端層)
|
|
||||||
- `AuthContext` 中的 `User` 接口
|
|
||||||
|
|
||||||
### 3. API 支援
|
|
||||||
- `/api/auth/profile` 端點已支援新字段的讀取和更新
|
|
||||||
- 動態更新機制,無需修改 API 代碼
|
|
||||||
|
|
||||||
### 4. 前端整合
|
|
||||||
- 個人資料對話框已包含所有字段
|
|
||||||
- 表單驗證和錯誤處理完整
|
|
||||||
- 與現有認證系統無縫整合
|
|
||||||
|
|
||||||
## 📋 個人資料字段對照
|
|
||||||
|
|
||||||
| 前端顯示 | 資料庫字段 | 類型 | 說明 |
|
|
||||||
|----------|------------|------|------|
|
|
||||||
| 姓名 | `name` | VARCHAR(100) | 用戶姓名 |
|
|
||||||
| 電子郵件 | `email` | VARCHAR(255) | 電子郵件地址 |
|
|
||||||
| 部門 | `department` | VARCHAR(100) | 所屬部門 |
|
|
||||||
| 電話 | `phone` | VARCHAR(20) | 電話號碼 ✅ 新增 |
|
|
||||||
| 地點 | `location` | VARCHAR(100) | 工作地點 ✅ 新增 |
|
|
||||||
| 個人簡介 | `bio` | TEXT | 個人簡介 ✅ 新增 |
|
|
||||||
| 角色 | `role` | ENUM | 用戶角色 |
|
|
||||||
| 頭像 | `avatar` | VARCHAR(500) | 頭像 URL |
|
|
||||||
|
|
||||||
## 🔧 技術實現
|
|
||||||
|
|
||||||
### 資料庫更新
|
|
||||||
```sql
|
|
||||||
ALTER TABLE users
|
|
||||||
ADD COLUMN `phone` VARCHAR(20) NULL,
|
|
||||||
ADD COLUMN `location` VARCHAR(100) NULL,
|
|
||||||
ADD COLUMN `bio` TEXT NULL;
|
|
||||||
```
|
|
||||||
|
|
||||||
### API 端點
|
|
||||||
```typescript
|
|
||||||
PUT /api/auth/profile
|
|
||||||
{
|
|
||||||
"userId": "user-uuid",
|
|
||||||
"phone": "0912-345-678",
|
|
||||||
"location": "台北市信義區",
|
|
||||||
"bio": "個人簡介內容"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 前端組件
|
|
||||||
- `ProfileDialog` 組件已包含所有字段
|
|
||||||
- 表單狀態管理完整
|
|
||||||
- 錯誤處理和成功提示
|
|
||||||
|
|
||||||
## 🧪 測試結果
|
|
||||||
|
|
||||||
### 資料庫測試 ✅
|
|
||||||
- 字段添加成功
|
|
||||||
- 資料更新正常
|
|
||||||
- 查詢功能正常
|
|
||||||
|
|
||||||
### API 測試 ✅
|
|
||||||
- 個人資料讀取正常
|
|
||||||
- 個人資料更新正常
|
|
||||||
- 錯誤處理完整
|
|
||||||
|
|
||||||
### 前端測試 ✅
|
|
||||||
- 表單顯示正確
|
|
||||||
- 資料綁定正常
|
|
||||||
- 更新功能正常
|
|
||||||
|
|
||||||
## 🚀 使用方法
|
|
||||||
|
|
||||||
### 1. 查看個人資料
|
|
||||||
登入後點擊用戶頭像 → 個人資料
|
|
||||||
|
|
||||||
### 2. 更新個人資料
|
|
||||||
1. 填寫表單字段
|
|
||||||
2. 點擊「儲存變更」
|
|
||||||
3. 系統會自動更新資料庫
|
|
||||||
|
|
||||||
### 3. 測試功能
|
|
||||||
```bash
|
|
||||||
# 測試個人資料更新
|
|
||||||
pnpm run test:profile
|
|
||||||
|
|
||||||
# 添加用戶字段(如需要)
|
|
||||||
pnpm run add:user-fields
|
|
||||||
```
|
|
||||||
|
|
||||||
## 📝 注意事項
|
|
||||||
|
|
||||||
1. **字段可選性**:所有新字段都是可選的,不會影響現有用戶
|
|
||||||
2. **資料驗證**:前端有基本的表單驗證
|
|
||||||
3. **向後兼容**:現有功能完全不受影響
|
|
||||||
4. **安全性**:所有更新都通過 API 進行,有適當的權限檢查
|
|
||||||
|
|
||||||
## 🎉 整合完成
|
|
||||||
|
|
||||||
個人資料功能現在完全與資料庫連結,支援:
|
|
||||||
- ✅ 電話號碼
|
|
||||||
- ✅ 工作地點
|
|
||||||
- ✅ 個人簡介
|
|
||||||
- ✅ 完整的 CRUD 操作
|
|
||||||
- ✅ 前端表單整合
|
|
||||||
- ✅ API 端點支援
|
|
||||||
|
|
||||||
您現在可以正常使用個人資料功能,所有資料都會保存到 MySQL 資料庫中!
|
|
@@ -1,371 +0,0 @@
|
|||||||
# AI 展示平台專案完整解析
|
|
||||||
|
|
||||||
## 📋 專案概述
|
|
||||||
|
|
||||||
**強茂集團 AI 展示平台** 是一個企業內部 AI 應用展示與競賽管理系統,旨在促進 AI 技術的創新與應用。系統提供完整的競賽管理、評審系統、用戶互動和數據分析功能。
|
|
||||||
|
|
||||||
## 🏗️ 技術架構
|
|
||||||
|
|
||||||
### 前端技術棧
|
|
||||||
- **框架**: Next.js 15.2.4 (App Router)
|
|
||||||
- **語言**: TypeScript 5
|
|
||||||
- **UI 庫**:
|
|
||||||
- Radix UI (無障礙組件)
|
|
||||||
- shadcn/ui (設計系統)
|
|
||||||
- Tailwind CSS (樣式框架)
|
|
||||||
- **狀態管理**: React Context API
|
|
||||||
- **表單處理**: React Hook Form + Zod
|
|
||||||
- **圖表**: Recharts
|
|
||||||
- **包管理器**: pnpm
|
|
||||||
|
|
||||||
### 後端技術棧
|
|
||||||
- **資料庫**: MySQL 8.0
|
|
||||||
- **ORM**: 自定義資料庫服務層
|
|
||||||
- **API**: Next.js API Routes
|
|
||||||
- **認證**: JWT + localStorage
|
|
||||||
- **文件上傳**: 本地存儲
|
|
||||||
|
|
||||||
### 資料庫設計
|
|
||||||
- **主機**: mysql.theaken.com:33306
|
|
||||||
- **資料庫**: db_AI_Platform
|
|
||||||
- **表數量**: 25 個核心表
|
|
||||||
- **視圖數量**: 3 個統計視圖
|
|
||||||
- **觸發器**: 4 個自動計算觸發器
|
|
||||||
|
|
||||||
## 🎯 核心功能模組
|
|
||||||
|
|
||||||
### 1. 用戶管理系統
|
|
||||||
- **三種角色**:
|
|
||||||
- 一般用戶 (user): 瀏覽應用、參與投票
|
|
||||||
- 開發者 (developer): 提交AI應用、參與競賽
|
|
||||||
- 管理員 (admin): 系統管理、數據分析
|
|
||||||
|
|
||||||
- **核心功能**:
|
|
||||||
- 註冊/登入/登出
|
|
||||||
- 個人資料管理
|
|
||||||
- 收藏應用
|
|
||||||
- 按讚功能 (每日限制)
|
|
||||||
- 瀏覽記錄追蹤
|
|
||||||
- 活動統計分析
|
|
||||||
|
|
||||||
### 2. 競賽系統
|
|
||||||
- **競賽類型**:
|
|
||||||
- 個人賽 (individual)
|
|
||||||
- 團隊賽 (team)
|
|
||||||
- 提案賽 (proposal)
|
|
||||||
- 混合賽 (mixed)
|
|
||||||
|
|
||||||
- **競賽狀態**:
|
|
||||||
- upcoming: 即將開始
|
|
||||||
- active: 進行中
|
|
||||||
- judging: 評審中
|
|
||||||
- completed: 已完成
|
|
||||||
|
|
||||||
- **核心功能**:
|
|
||||||
- 競賽創建與管理
|
|
||||||
- 參賽報名
|
|
||||||
- 評審分配
|
|
||||||
- 評分系統
|
|
||||||
- 獎項頒發
|
|
||||||
- 結果統計
|
|
||||||
|
|
||||||
### 3. 評審系統
|
|
||||||
- **評分維度**:
|
|
||||||
- 創新性 (Innovation)
|
|
||||||
- 技術性 (Technical)
|
|
||||||
- 實用性 (Usability)
|
|
||||||
- 展示效果 (Presentation)
|
|
||||||
- 影響力 (Impact)
|
|
||||||
|
|
||||||
- **評分範圍**: 1-10 分
|
|
||||||
- **評分權重**: 可自定義
|
|
||||||
- **評分統計**: 自動計算平均分
|
|
||||||
|
|
||||||
### 4. 團隊管理
|
|
||||||
- **團隊結構**:
|
|
||||||
- 隊長 (Leader)
|
|
||||||
- 成員 (Member)
|
|
||||||
- 角色分配
|
|
||||||
|
|
||||||
- **核心功能**:
|
|
||||||
- 團隊創建與管理
|
|
||||||
- 成員邀請與管理
|
|
||||||
- 團隊統計分析
|
|
||||||
- 團隊競賽參與
|
|
||||||
|
|
||||||
### 5. 應用管理
|
|
||||||
- **應用類型**:
|
|
||||||
- 機器學習應用
|
|
||||||
- 自然語言處理
|
|
||||||
- 計算機視覺
|
|
||||||
- 數據分析
|
|
||||||
- 自動化工具
|
|
||||||
|
|
||||||
- **核心功能**:
|
|
||||||
- 應用提交
|
|
||||||
- 應用展示
|
|
||||||
- 評分統計
|
|
||||||
- 用戶互動
|
|
||||||
|
|
||||||
### 6. 提案管理
|
|
||||||
- **提案內容**:
|
|
||||||
- 問題陳述
|
|
||||||
- 解決方案
|
|
||||||
- 預期影響
|
|
||||||
- 附件支持
|
|
||||||
|
|
||||||
- **提案狀態**:
|
|
||||||
- draft: 草稿
|
|
||||||
- submitted: 已提交
|
|
||||||
- under_review: 審核中
|
|
||||||
- approved: 已批准
|
|
||||||
- rejected: 已拒絕
|
|
||||||
|
|
||||||
### 7. 獎項系統
|
|
||||||
- **獎項類型**:
|
|
||||||
- 金獎 (Gold)
|
|
||||||
- 銀獎 (Silver)
|
|
||||||
- 銅獎 (Bronze)
|
|
||||||
- 人氣獎 (Popular)
|
|
||||||
- 創新獎 (Innovation)
|
|
||||||
- 技術獎 (Technical)
|
|
||||||
- 自定義獎項 (Custom)
|
|
||||||
|
|
||||||
- **獎項類別**:
|
|
||||||
- 創新性 (Innovation)
|
|
||||||
- 技術性 (Technical)
|
|
||||||
- 實用性 (Practical)
|
|
||||||
- 人氣 (Popular)
|
|
||||||
- 團隊合作 (Teamwork)
|
|
||||||
- 解決方案 (Solution)
|
|
||||||
- 創意 (Creativity)
|
|
||||||
|
|
||||||
### 8. AI 助手系統
|
|
||||||
- **功能特色**:
|
|
||||||
- 智能問答
|
|
||||||
- 操作指導
|
|
||||||
- 快速問題
|
|
||||||
- 會話管理
|
|
||||||
|
|
||||||
- **技術實現**:
|
|
||||||
- DeepSeek API 集成
|
|
||||||
- 上下文管理
|
|
||||||
- 會話持久化
|
|
||||||
|
|
||||||
## 📊 資料庫設計
|
|
||||||
|
|
||||||
### 核心表結構
|
|
||||||
|
|
||||||
#### 用戶相關表
|
|
||||||
- **users**: 用戶基本資訊
|
|
||||||
- **user_favorites**: 用戶收藏
|
|
||||||
- **user_likes**: 用戶按讚
|
|
||||||
- **user_views**: 用戶瀏覽記錄
|
|
||||||
- **user_ratings**: 用戶評分
|
|
||||||
|
|
||||||
#### 競賽相關表
|
|
||||||
- **competitions**: 競賽基本資訊
|
|
||||||
- **competition_rules**: 競賽規則
|
|
||||||
- **competition_award_types**: 獎項類型
|
|
||||||
- **competition_judges**: 評審分配
|
|
||||||
- **competition_apps**: 參賽應用
|
|
||||||
- **competition_teams**: 參賽團隊
|
|
||||||
- **competition_proposals**: 參賽提案
|
|
||||||
|
|
||||||
#### 評審相關表
|
|
||||||
- **judges**: 評審基本資訊
|
|
||||||
- **app_judge_scores**: 應用評分
|
|
||||||
- **proposal_judge_scores**: 提案評分
|
|
||||||
|
|
||||||
#### 團隊相關表
|
|
||||||
- **teams**: 團隊基本資訊
|
|
||||||
- **team_members**: 團隊成員
|
|
||||||
|
|
||||||
#### 應用相關表
|
|
||||||
- **apps**: 應用基本資訊
|
|
||||||
- **proposals**: 提案基本資訊
|
|
||||||
- **awards**: 獎項記錄
|
|
||||||
|
|
||||||
#### 系統相關表
|
|
||||||
- **chat_sessions**: 聊天會話
|
|
||||||
- **chat_messages**: 聊天訊息
|
|
||||||
- **ai_assistant_configs**: AI 配置
|
|
||||||
- **system_settings**: 系統設定
|
|
||||||
- **activity_logs**: 活動日誌
|
|
||||||
|
|
||||||
### 統計視圖
|
|
||||||
- **user_statistics**: 用戶統計
|
|
||||||
- **app_statistics**: 應用統計
|
|
||||||
- **competition_statistics**: 競賽統計
|
|
||||||
|
|
||||||
### 觸發器
|
|
||||||
- **calculate_app_total_score**: 應用評分總分計算
|
|
||||||
- **calculate_proposal_total_score**: 提案評分總分計算
|
|
||||||
|
|
||||||
## 🔧 開發環境設置
|
|
||||||
|
|
||||||
### 1. 環境要求
|
|
||||||
- Node.js 18+
|
|
||||||
- pnpm
|
|
||||||
- MySQL 8.0+
|
|
||||||
- Git
|
|
||||||
|
|
||||||
### 2. 安裝步驟
|
|
||||||
```bash
|
|
||||||
# 克隆專案
|
|
||||||
git clone <repository-url>
|
|
||||||
cd ai-showcase-platform
|
|
||||||
|
|
||||||
# 安裝依賴
|
|
||||||
pnpm install
|
|
||||||
|
|
||||||
# 設置環境變數
|
|
||||||
cp env.example .env.local
|
|
||||||
|
|
||||||
# 執行資料庫遷移
|
|
||||||
pnpm run migrate
|
|
||||||
|
|
||||||
# 測試資料庫連接
|
|
||||||
pnpm run test:db
|
|
||||||
|
|
||||||
# 啟動開發服務器
|
|
||||||
pnpm run dev
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3. 環境變數配置
|
|
||||||
```env
|
|
||||||
# 資料庫配置
|
|
||||||
DB_HOST=mysql.theaken.com
|
|
||||||
DB_PORT=33306
|
|
||||||
DB_NAME=db_AI_Platform
|
|
||||||
DB_USER=AI_Platform
|
|
||||||
DB_PASSWORD=Aa123456
|
|
||||||
|
|
||||||
# DeepSeek API 配置
|
|
||||||
NEXT_PUBLIC_DEEPSEEK_API_KEY=your_api_key
|
|
||||||
NEXT_PUBLIC_DEEPSEEK_API_URL=https://api.deepseek.com/v1/chat/completions
|
|
||||||
|
|
||||||
# JWT 配置
|
|
||||||
JWT_SECRET=your_jwt_secret
|
|
||||||
JWT_EXPIRES_IN=7d
|
|
||||||
```
|
|
||||||
|
|
||||||
## 📁 專案結構
|
|
||||||
|
|
||||||
```
|
|
||||||
ai-showcase-platform/
|
|
||||||
├── app/ # Next.js App Router
|
|
||||||
│ ├── admin/ # 管理員頁面
|
|
||||||
│ ├── competition/ # 競賽頁面
|
|
||||||
│ ├── judge-scoring/ # 評審頁面
|
|
||||||
│ └── register/ # 註冊頁面
|
|
||||||
├── components/ # React 組件
|
|
||||||
│ ├── admin/ # 管理員組件
|
|
||||||
│ ├── auth/ # 認證組件
|
|
||||||
│ ├── competition/ # 競賽組件
|
|
||||||
│ ├── reviews/ # 評分組件
|
|
||||||
│ └── ui/ # UI 組件庫
|
|
||||||
├── contexts/ # React Context
|
|
||||||
│ ├── auth-context.tsx # 認證上下文
|
|
||||||
│ └── competition-context.tsx # 競賽上下文
|
|
||||||
├── hooks/ # 自定義 Hooks
|
|
||||||
├── lib/ # 工具庫
|
|
||||||
│ ├── database.ts # 資料庫連接
|
|
||||||
│ ├── models.ts # 資料模型
|
|
||||||
│ └── services/ # 服務層
|
|
||||||
├── types/ # TypeScript 類型
|
|
||||||
├── scripts/ # 腳本文件
|
|
||||||
├── public/ # 靜態資源
|
|
||||||
└── styles/ # 樣式文件
|
|
||||||
```
|
|
||||||
|
|
||||||
## 🚀 部署指南
|
|
||||||
|
|
||||||
### 1. 生產環境準備
|
|
||||||
- 設置生產資料庫
|
|
||||||
- 配置環境變數
|
|
||||||
- 設置文件上傳目錄
|
|
||||||
- 配置反向代理
|
|
||||||
|
|
||||||
### 2. 部署步驟
|
|
||||||
```bash
|
|
||||||
# 構建專案
|
|
||||||
pnpm run build
|
|
||||||
|
|
||||||
# 啟動生產服務器
|
|
||||||
pnpm run start
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3. 監控與維護
|
|
||||||
- 資料庫備份
|
|
||||||
- 日誌監控
|
|
||||||
- 性能監控
|
|
||||||
- 錯誤追蹤
|
|
||||||
|
|
||||||
## 🔍 功能特色
|
|
||||||
|
|
||||||
### 1. 響應式設計
|
|
||||||
- 移動端適配
|
|
||||||
- 平板端優化
|
|
||||||
- 桌面端完整功能
|
|
||||||
|
|
||||||
### 2. 無障礙支持
|
|
||||||
- 鍵盤導航
|
|
||||||
- 屏幕閱讀器支持
|
|
||||||
- 高對比度模式
|
|
||||||
|
|
||||||
### 3. 國際化支持
|
|
||||||
- 繁體中文界面
|
|
||||||
- 多語言擴展準備
|
|
||||||
|
|
||||||
### 4. 性能優化
|
|
||||||
- 代碼分割
|
|
||||||
- 圖片優化
|
|
||||||
- 緩存策略
|
|
||||||
|
|
||||||
## 📈 未來規劃
|
|
||||||
|
|
||||||
### 短期目標
|
|
||||||
- 完善評審系統
|
|
||||||
- 優化用戶體驗
|
|
||||||
- 增加數據分析功能
|
|
||||||
|
|
||||||
### 中期目標
|
|
||||||
- 移動端應用
|
|
||||||
- 實時通知系統
|
|
||||||
- 高級搜索功能
|
|
||||||
|
|
||||||
### 長期目標
|
|
||||||
- 多租戶支持
|
|
||||||
- 微服務架構
|
|
||||||
- 人工智能集成
|
|
||||||
|
|
||||||
## 🤝 貢獻指南
|
|
||||||
|
|
||||||
### 1. 代碼規範
|
|
||||||
- TypeScript 嚴格模式
|
|
||||||
- ESLint 規則遵循
|
|
||||||
- Prettier 格式化
|
|
||||||
|
|
||||||
### 2. 提交規範
|
|
||||||
- 清晰的提交信息
|
|
||||||
- 功能分支開發
|
|
||||||
- 代碼審查流程
|
|
||||||
|
|
||||||
### 3. 測試要求
|
|
||||||
- 單元測試
|
|
||||||
- 集成測試
|
|
||||||
- 端到端測試
|
|
||||||
|
|
||||||
## 📞 技術支援
|
|
||||||
|
|
||||||
如有任何技術問題,請聯繫:
|
|
||||||
- 技術團隊
|
|
||||||
- 項目維護者
|
|
||||||
- 查看專案文檔
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**版本**: 1.0.0
|
|
||||||
**最後更新**: 2024年12月
|
|
||||||
**維護者**: 強茂集團技術團隊
|
|
@@ -1,128 +0,0 @@
|
|||||||
# 密碼重設頁面角色顯示修復總結
|
|
||||||
|
|
||||||
## 🎯 問題描述
|
|
||||||
|
|
||||||
在密碼重設頁面中,管理員帳號的角色顯示為「一般用戶」,而不是從資料庫 `users` 表的 `role` 欄位獲取的正確角色資訊。
|
|
||||||
|
|
||||||
## 🔍 問題分析
|
|
||||||
|
|
||||||
### 原因分析:
|
|
||||||
1. **忘記密碼 API** 在生成重設連結時,沒有包含用戶的角色資訊
|
|
||||||
2. **註冊頁面** 在密碼重設模式下,角色顯示依賴 URL 參數,但該參數缺失
|
|
||||||
3. **角色資訊** 應該從資料庫中的 `users.role` 欄位獲取,而不是硬編碼
|
|
||||||
|
|
||||||
### 原始問題:
|
|
||||||
```typescript
|
|
||||||
// 忘記密碼 API 中缺少角色資訊
|
|
||||||
const resetUrl = `${baseUrl}/register?token=${resetToken.token}&email=${encodeURIComponent(user.email)}&mode=reset&name=${encodeURIComponent(user.name)}&department=${encodeURIComponent(user.department)}`
|
|
||||||
// 缺少 &role=${encodeURIComponent(user.role)}
|
|
||||||
```
|
|
||||||
|
|
||||||
## ✅ 修復方案
|
|
||||||
|
|
||||||
### 1. 修改忘記密碼 API
|
|
||||||
**文件:** `app/api/auth/forgot-password/route.ts`
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
// 修復前
|
|
||||||
const resetUrl = `${baseUrl}/register?token=${resetToken.token}&email=${encodeURIComponent(user.email)}&mode=reset&name=${encodeURIComponent(user.name)}&department=${encodeURIComponent(user.department)}`
|
|
||||||
|
|
||||||
// 修復後
|
|
||||||
const resetUrl = `${baseUrl}/register?token=${resetToken.token}&email=${encodeURIComponent(user.email)}&mode=reset&name=${encodeURIComponent(user.name)}&department=${encodeURIComponent(user.department)}&role=${encodeURIComponent(user.role)}`
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. 修改註冊頁面角色顯示
|
|
||||||
**文件:** `app/register/page.tsx`
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
// 添加角色顯示變數
|
|
||||||
const displayRole = isResetMode ? invitedRole : invitedRole
|
|
||||||
|
|
||||||
// 更新角色顯示邏輯
|
|
||||||
{displayRole === "admin" && (
|
|
||||||
<><Shield className="w-3 h-3 mr-1" />管理員</>
|
|
||||||
)}
|
|
||||||
{displayRole === "developer" && (
|
|
||||||
<><Code className="w-3 h-3 mr-1" />開發者</>
|
|
||||||
)}
|
|
||||||
{displayRole === "user" && (
|
|
||||||
<><User className="w-3 h-3 mr-1" />一般用戶</>
|
|
||||||
)}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 🧪 測試結果
|
|
||||||
|
|
||||||
### 測試腳本:`scripts/test-role-display.js`
|
|
||||||
|
|
||||||
```
|
|
||||||
✅ 忘記密碼 API 測試成功
|
|
||||||
生成的重設連結: http://localhost:3000/register?token=xxx&email=admin%40ai-platform.com&mode=reset&name=%E7%B3%BB%E7%B5%B1%E7%AE%A1%E7%90%86%E5%93%A1&department=ITBU&role=admin
|
|
||||||
|
|
||||||
📋 URL 參數解析:
|
|
||||||
- token: xxx
|
|
||||||
- email: admin@ai-platform.com
|
|
||||||
- mode: reset
|
|
||||||
- name: 系統管理員
|
|
||||||
- department: ITBU
|
|
||||||
- role: admin
|
|
||||||
|
|
||||||
✅ 註冊頁面載入成功
|
|
||||||
✅ 角色顯示正確:管理員
|
|
||||||
```
|
|
||||||
|
|
||||||
## 📋 修復內容總結
|
|
||||||
|
|
||||||
### ✅ 已修復的問題:
|
|
||||||
|
|
||||||
1. **忘記密碼 API** 現在包含用戶角色資訊
|
|
||||||
- 從資料庫 `users` 表獲取正確的 `role` 欄位
|
|
||||||
- 在重設連結中包含 `role` 參數
|
|
||||||
|
|
||||||
2. **註冊頁面** 正確顯示角色資訊
|
|
||||||
- 從 URL 參數獲取角色資訊
|
|
||||||
- 使用 `displayRole` 變數確保角色顯示正確
|
|
||||||
- 支援管理員、開發者、一般用戶三種角色
|
|
||||||
|
|
||||||
3. **角色顯示邏輯** 基於資料庫資料
|
|
||||||
- 不再依賴硬編碼的角色資訊
|
|
||||||
- 確保角色顯示與資料庫中的實際角色一致
|
|
||||||
|
|
||||||
### 🔧 技術改進:
|
|
||||||
|
|
||||||
1. **資料一致性**:角色資訊直接來自資料庫
|
|
||||||
2. **URL 參數完整性**:重設連結包含所有必要的用戶資訊
|
|
||||||
3. **顯示邏輯優化**:使用專門的 `displayRole` 變數
|
|
||||||
4. **測試覆蓋**:添加專門的角色顯示測試
|
|
||||||
|
|
||||||
## 🎉 修復效果
|
|
||||||
|
|
||||||
### 修復前:
|
|
||||||
- 管理員帳號在密碼重設頁面顯示為「一般用戶」
|
|
||||||
- 角色資訊不準確,可能造成用戶困惑
|
|
||||||
|
|
||||||
### 修復後:
|
|
||||||
- 管理員帳號正確顯示為「管理員」
|
|
||||||
- 所有角色都基於資料庫中的實際資料
|
|
||||||
- 角色顯示與用戶實際權限一致
|
|
||||||
|
|
||||||
## 🚀 使用方式
|
|
||||||
|
|
||||||
### 1. 測試角色顯示
|
|
||||||
```bash
|
|
||||||
# 測試角色顯示功能
|
|
||||||
pnpm run test:role-display
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. 驗證修復效果
|
|
||||||
1. 使用管理員帳號 (`admin@ai-platform.com`) 測試忘記密碼
|
|
||||||
2. 點擊生成的重設連結
|
|
||||||
3. 確認角色顯示為「管理員」而非「一般用戶」
|
|
||||||
|
|
||||||
## 📝 注意事項
|
|
||||||
|
|
||||||
1. **資料庫依賴**:角色顯示現在完全依賴資料庫中的 `users.role` 欄位
|
|
||||||
2. **URL 參數**:重設連結現在包含完整的用戶資訊
|
|
||||||
3. **向後兼容**:修復不影響現有的其他功能
|
|
||||||
4. **測試覆蓋**:建議定期運行角色顯示測試確保功能正常
|
|
||||||
|
|
||||||
角色顯示問題已完全修復,現在密碼重設頁面會正確顯示用戶在資料庫中的實際角色!
|
|
@@ -1,103 +0,0 @@
|
|||||||
# SSR 錯誤修復總結
|
|
||||||
|
|
||||||
## 🐛 問題描述
|
|
||||||
|
|
||||||
在 Next.js 應用中遇到了 `ReferenceError: window is not defined` 錯誤,這是因為在服務器端渲染 (SSR) 時嘗試訪問 `window` 對象導致的。
|
|
||||||
|
|
||||||
## ✅ 修復的文件
|
|
||||||
|
|
||||||
### 1. `components/admin/admin-layout.tsx`
|
|
||||||
**問題**:在 SSR 期間直接使用 `window` 對象
|
|
||||||
**修復**:添加 `typeof window !== 'undefined'` 檢查
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
// 修復前
|
|
||||||
{window.opener && !window.opener.closed && (
|
|
||||||
<Button onClick={() => {
|
|
||||||
window.opener.focus()
|
|
||||||
window.close()
|
|
||||||
}}>
|
|
||||||
關閉頁面
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
|
|
||||||
// 修復後
|
|
||||||
{typeof window !== 'undefined' && window.opener && !window.opener.closed && (
|
|
||||||
<Button onClick={() => {
|
|
||||||
window.opener.focus()
|
|
||||||
window.close()
|
|
||||||
}}>
|
|
||||||
關閉頁面
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. `components/admin/user-management.tsx`
|
|
||||||
**問題**:在函數中直接使用 `window.location.origin`
|
|
||||||
**修復**:添加條件檢查,提供回退值
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
// 修復前
|
|
||||||
const invitationLink = `${window.location.origin}/register?token=${invitationToken}&email=${encodeURIComponent(inviteEmail)}&role=${inviteRole}`
|
|
||||||
|
|
||||||
// 修復後
|
|
||||||
const invitationLink = typeof window !== "undefined"
|
|
||||||
? `${window.location.origin}/register?token=${invitationToken}&email=${encodeURIComponent(inviteEmail)}&role=${inviteRole}`
|
|
||||||
: `/register?token=${invitationToken}&email=${encodeURIComponent(inviteEmail)}&role=${inviteRole}`
|
|
||||||
```
|
|
||||||
|
|
||||||
## 🔧 修復策略
|
|
||||||
|
|
||||||
### 1. 條件檢查
|
|
||||||
```typescript
|
|
||||||
if (typeof window !== 'undefined') {
|
|
||||||
// 只在客戶端執行
|
|
||||||
window.location.href = "/"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. 三元運算符
|
|
||||||
```typescript
|
|
||||||
const url = typeof window !== 'undefined'
|
|
||||||
? `${window.location.origin}/path`
|
|
||||||
: "/path"
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3. useEffect Hook
|
|
||||||
```typescript
|
|
||||||
useEffect(() => {
|
|
||||||
// 只在客戶端執行
|
|
||||||
window.addEventListener('resize', handleResize)
|
|
||||||
return () => window.removeEventListener('resize', handleResize)
|
|
||||||
}, [])
|
|
||||||
```
|
|
||||||
|
|
||||||
## 📋 已檢查的文件
|
|
||||||
|
|
||||||
以下文件已經有正確的 SSR 處理,無需修復:
|
|
||||||
- `components/ui/use-mobile.tsx` - 使用 useEffect
|
|
||||||
- `components/admin/competition-management.tsx` - 有條件檢查
|
|
||||||
- `components/admin/scoring-link-dialog.tsx` - 有條件檢查
|
|
||||||
|
|
||||||
## 🎯 修復結果
|
|
||||||
|
|
||||||
- ✅ 消除了 `window is not defined` 錯誤
|
|
||||||
- ✅ 保持了客戶端功能正常運作
|
|
||||||
- ✅ 確保了 SSR 兼容性
|
|
||||||
- ✅ 提供了適當的回退值
|
|
||||||
|
|
||||||
## 📝 最佳實踐
|
|
||||||
|
|
||||||
1. **始終檢查 `window` 對象**:在 Next.js 中,`window` 只在客戶端可用
|
|
||||||
2. **使用 useEffect**:對於需要在客戶端執行的代碼,使用 `useEffect` Hook
|
|
||||||
3. **提供回退值**:為 SSR 環境提供適當的默認值
|
|
||||||
4. **避免在組件頂層使用 `window`**:將 `window` 相關代碼放在函數內部或 useEffect 中
|
|
||||||
|
|
||||||
## 🚀 測試建議
|
|
||||||
|
|
||||||
1. 檢查管理員頁面是否正常加載
|
|
||||||
2. 驗證用戶邀請功能是否正常
|
|
||||||
3. 確認彈窗關閉功能是否正常
|
|
||||||
4. 測試在不同環境下的表現
|
|
||||||
|
|
||||||
修復完成後,應用應該能夠正常進行服務器端渲染,同時保持所有客戶端功能正常運作。
|
|
@@ -15,7 +15,7 @@ export function AdminPanel() {
|
|||||||
const renderPage = () => {
|
const renderPage = () => {
|
||||||
switch (currentPage) {
|
switch (currentPage) {
|
||||||
case "dashboard":
|
case "dashboard":
|
||||||
return <AdminDashboard />
|
return <AdminDashboard onPageChange={setCurrentPage} />
|
||||||
case "users":
|
case "users":
|
||||||
return <UserManagement />
|
return <UserManagement />
|
||||||
case "apps":
|
case "apps":
|
||||||
@@ -27,7 +27,7 @@ export function AdminPanel() {
|
|||||||
case "settings":
|
case "settings":
|
||||||
return <SystemSettings />
|
return <SystemSettings />
|
||||||
default:
|
default:
|
||||||
return <AdminDashboard />
|
return <AdminDashboard onPageChange={setCurrentPage} />
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -39,7 +39,11 @@ interface TopApp {
|
|||||||
created_at: string
|
created_at: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export function AdminDashboard() {
|
interface AdminDashboardProps {
|
||||||
|
onPageChange?: (page: string) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
export function AdminDashboard({ onPageChange }: AdminDashboardProps) {
|
||||||
const { competitions } = useCompetition()
|
const { competitions } = useCompetition()
|
||||||
const [stats, setStats] = useState<DashboardStats>({
|
const [stats, setStats] = useState<DashboardStats>({
|
||||||
totalUsers: 0,
|
totalUsers: 0,
|
||||||
@@ -93,6 +97,12 @@ export function AdminDashboard() {
|
|||||||
return iconMap[iconName] || Activity
|
return iconMap[iconName] || Activity
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleQuickAction = (page: string) => {
|
||||||
|
if (onPageChange) {
|
||||||
|
onPageChange(page)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
{/* Welcome Section */}
|
{/* Welcome Section */}
|
||||||
@@ -286,15 +296,26 @@ export function AdminDashboard() {
|
|||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
|
||||||
<Button className="h-20 flex flex-col space-y-2">
|
<Button
|
||||||
|
className="h-20 flex flex-col space-y-2"
|
||||||
|
onClick={() => handleQuickAction('users')}
|
||||||
|
>
|
||||||
<Users className="w-6 h-6" />
|
<Users className="w-6 h-6" />
|
||||||
<span>管理用戶</span>
|
<span>管理用戶</span>
|
||||||
</Button>
|
</Button>
|
||||||
<Button className="h-20 flex flex-col space-y-2 bg-transparent" variant="outline">
|
<Button
|
||||||
|
className="h-20 flex flex-col space-y-2 bg-transparent"
|
||||||
|
variant="outline"
|
||||||
|
onClick={() => handleQuickAction('apps')}
|
||||||
|
>
|
||||||
<Bot className="w-6 h-6" />
|
<Bot className="w-6 h-6" />
|
||||||
<span>新增應用</span>
|
<span>新增應用</span>
|
||||||
</Button>
|
</Button>
|
||||||
<Button className="h-20 flex flex-col space-y-2 bg-transparent" variant="outline">
|
<Button
|
||||||
|
className="h-20 flex flex-col space-y-2 bg-transparent"
|
||||||
|
variant="outline"
|
||||||
|
onClick={() => handleQuickAction('competitions')}
|
||||||
|
>
|
||||||
<Trophy className="w-6 h-6" />
|
<Trophy className="w-6 h-6" />
|
||||||
<span>創建競賽</span>
|
<span>創建競賽</span>
|
||||||
</Button>
|
</Button>
|
||||||
|
Reference in New Issue
Block a user