diff --git a/app/admin/page.tsx b/app/admin/page.tsx index cbd6d91..e9d0166 100644 --- a/app/admin/page.tsx +++ b/app/admin/page.tsx @@ -1,6 +1,6 @@ "use client" -import { useState } from "react" +import { useState, useEffect } from "react" import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card" import { Badge } from "@/components/ui/badge" import { Button } from "@/components/ui/button" @@ -22,53 +22,23 @@ import { Avatar, AvatarFallback } from "@/components/ui/avatar" import { Switch } from "@/components/ui/switch" import { Users, Settings, Target, MessageSquare, Plus, Edit, Trash2, Shield, Database, Bell } from "lucide-react" -// Mock data with colors -const users = [ - { - id: 1, - name: "陳雅雯", - email: "sarah.chen@company.com", - role: "executive", - status: "active", - lastLogin: "2024-02-10", - department: "業務部", - position: "業務副總", - color: "emerald", - }, - { - id: 2, - name: "王志明", - email: "mike.wang@company.com", - role: "manager", - status: "active", - lastLogin: "2024-02-09", - department: "技術部", - position: "技術長", - color: "blue", - }, - { - id: 3, - name: "李美玲", - email: "lisa.lee@company.com", - role: "executive", - status: "inactive", - lastLogin: "2024-01-28", - department: "行銷部", - position: "行銷長", - color: "purple", - }, - { - id: 4, - name: "張建國", - email: "john.chang@company.com", - role: "manager", - status: "active", - lastLogin: "2024-02-08", - department: "研發部", - position: "研發總監", - color: "orange", - }, -] +// 用戶介面 +interface User { + id: string + name: string + email: string + role: "executive" | "manager" | "hr" + avatar_url?: string + created_at: string + updated_at: string +} + +// 用戶顏色映射 +const getUserColor = (id: string) => { + const colors = ["emerald", "blue", "purple", "orange", "cyan", "pink", "indigo", "yellow"] + const index = id.charCodeAt(id.length - 1) % colors.length + return colors[index] +} const kpiTemplates = [ { id: 1, name: "營收成長率", category: "財務", defaultWeight: 30, isActive: true, usageCount: 15, color: "emerald" }, @@ -106,15 +76,103 @@ export default function AdminPanel() { const [activeTab, setActiveTab] = useState("users") const [isDialogOpen, setIsDialogOpen] = useState(false) const [dialogType, setDialogType] = useState("") + const [users, setUsers] = useState([]) + const [loading, setLoading] = useState(true) + const [error, setError] = useState(null) + const [editingUser, setEditingUser] = useState(null) + const [editForm, setEditForm] = useState({ + name: "", + email: "", + role: "manager" as "executive" | "manager" | "hr" + }) + + // 載入用戶數據 + useEffect(() => { + fetchUsers() + }, []) + + const fetchUsers = async () => { + try { + setLoading(true) + const response = await fetch('/api/users') + if (!response.ok) { + throw new Error('載入用戶數據失敗') + } + const data = await response.json() + setUsers(data) + } catch (err) { + setError(err instanceof Error ? err.message : '載入用戶數據失敗') + } finally { + setLoading(false) + } + } const handleOpenDialog = (type: string) => { setDialogType(type) setIsDialogOpen(true) } + const handleEditUser = (user: User) => { + setEditingUser(user) + setEditForm({ + name: user.name, + email: user.email, + role: user.role + }) + setDialogType("edit-user") + setIsDialogOpen(true) + } + + const handleUpdateUser = async () => { + if (!editingUser) return + + try { + const response = await fetch(`/api/users/${editingUser.id}`, { + method: 'PUT', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(editForm), + }) + + if (!response.ok) { + throw new Error('更新用戶失敗') + } + + // 重新載入用戶數據 + await fetchUsers() + setIsDialogOpen(false) + setEditingUser(null) + setEditForm({ name: "", email: "", role: "manager" }) + } catch (err) { + setError(err instanceof Error ? err.message : '更新用戶失敗') + } + } + + const handleDeleteUser = async (userId: string) => { + if (!confirm('確定要刪除此用戶嗎?此操作無法復原。')) { + return + } + + try { + const response = await fetch(`/api/users/${userId}`, { + method: 'DELETE', + }) + + if (!response.ok) { + throw new Error('刪除用戶失敗') + } + + // 重新載入用戶數據 + await fetchUsers() + } catch (err) { + setError(err instanceof Error ? err.message : '刪除用戶失敗') + } + } + const adminStats = { totalUsers: users.length, - activeUsers: users.filter((u) => u.status === "active").length, + activeUsers: users.length, // 所有用戶都視為活躍 totalKPIs: kpiTemplates.length, activeKPIs: kpiTemplates.filter((k) => k.isActive).length, totalQuestions: questionTemplates.length, @@ -242,74 +300,97 @@ export default function AdminPanel() { 新增用戶 - - - - 用戶 - 部門/職位 - 角色 - 狀態 - 最後登入 - 操作 - - - - {users.map((user) => ( - - -
- - - {user.name.charAt(0)} - - -
-
{user.name}
-
{user.email}
-
-
-
- -
-
{user.department}
-
{user.position}
-
-
- - - {user.role === "executive" ? "高階主管" : user.role === "manager" ? "經理" : "HR"} - - - - - {user.status === "active" ? "啟用" : "停用"} - - - {user.lastLogin} - -
- - -
-
+ + {error && ( +
+ {error} +
+ )} + + {loading ? ( +
+
+

載入用戶數據中...

+
+ ) : ( +
+ + + 用戶 + 角色 + 建立時間 + 操作 - ))} - -
+ + + {users.map((user) => { + const userColor = getUserColor(user.id) + return ( + + +
+ + + {user.name.charAt(0)} + + +
+
{user.name}
+
{user.email}
+
+
+
+ + + {user.role === "executive" ? "高階主管" : user.role === "manager" ? "經理" : "HR"} + + + + {new Date(user.created_at).toLocaleDateString('zh-TW')} + + +
+ + +
+
+
+ ) + })} +
+ + )} {/* KPI Templates Tab */} @@ -474,36 +555,56 @@ export default function AdminPanel() { {dialogType === "user" ? "新增用戶" - : dialogType === "kpi" - ? "新增 KPI 模板" - : dialogType === "question" - ? "新增審查問題" - : "備份資料"} + : dialogType === "edit-user" + ? "編輯用戶" + : dialogType === "kpi" + ? "新增 KPI 模板" + : dialogType === "question" + ? "新增審查問題" + : "備份資料"} {dialogType === "user" ? "建立新的系統用戶帳號" - : dialogType === "kpi" - ? "建立新的 KPI 模板" - : dialogType === "question" - ? "建立新的審查問題" - : "備份系統資料到安全位置"} + : dialogType === "edit-user" + ? "修改用戶資訊" + : dialogType === "kpi" + ? "建立新的 KPI 模板" + : dialogType === "question" + ? "建立新的審查問題" + : "備份系統資料到安全位置"}
- {dialogType === "user" && ( + {(dialogType === "user" || dialogType === "edit-user") && ( <>
- + setEditForm({ ...editForm, name: e.target.value })} + />
- + setEditForm({ ...editForm, email: e.target.value })} + />
- + setEditForm({ ...editForm, role: value }) + } + > @@ -514,10 +615,6 @@ export default function AdminPanel() {
-
- - -
)} {dialogType === "kpi" && ( @@ -593,8 +690,9 @@ export default function AdminPanel() { diff --git a/app/api/users/[id]/route.ts b/app/api/users/[id]/route.ts new file mode 100644 index 0000000..72a0590 --- /dev/null +++ b/app/api/users/[id]/route.ts @@ -0,0 +1,62 @@ +import { NextRequest, NextResponse } from 'next/server' +import { userService } from '@/lib/database' + +// 更新用戶 +export async function PUT( + request: NextRequest, + { params }: { params: { id: string } } +) { + try { + const body = await request.json() + const { name, email, role, avatar_url } = body + + // 驗證必填欄位 + if (!name || !email || !role) { + return NextResponse.json( + { error: '姓名、電子郵件和角色為必填欄位' }, + { status: 400 } + ) + } + + // 驗證角色 + const validRoles = ['executive', 'manager', 'hr'] + if (!validRoles.includes(role)) { + return NextResponse.json( + { error: '無效的角色類型' }, + { status: 400 } + ) + } + + const updatedUser = await userService.updateUser(params.id, { + name, + email, + role, + avatar_url + }) + + return NextResponse.json(updatedUser) + } catch (error) { + console.error('更新用戶失敗:', error) + return NextResponse.json( + { error: '更新用戶失敗' }, + { status: 500 } + ) + } +} + +// 刪除用戶 +export async function DELETE( + request: NextRequest, + { params }: { params: { id: string } } +) { + try { + await userService.deleteUser(params.id) + return NextResponse.json({ message: '用戶刪除成功' }) + } catch (error) { + console.error('刪除用戶失敗:', error) + return NextResponse.json( + { error: '刪除用戶失敗' }, + { status: 500 } + ) + } +} \ No newline at end of file