"use client" import { useState, useEffect } from "react" import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card" import { Button } from "@/components/ui/button" import { Input } from "@/components/ui/input" import { Badge } from "@/components/ui/badge" import { Avatar, AvatarFallback } from "@/components/ui/avatar" import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select" import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from "@/components/ui/dialog" import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs" import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table" import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@/components/ui/dropdown-menu" import { Label } from "@/components/ui/label" import { Alert, AlertDescription } from "@/components/ui/alert" import { Search, MoreHorizontal, UserPlus, Edit, Trash2, Shield, Eye, Calendar, Activity, User, Mail, Building, Loader2, CheckCircle, AlertTriangle, Clock, RefreshCw, Copy, Link, ExternalLink, Code, Users, } from "lucide-react" // User data - empty for production const initialMockUsers: any[] = [] export function UserManagement() { const [users, setUsers] = useState(initialMockUsers) const [searchTerm, setSearchTerm] = useState("") const [selectedDepartment, setSelectedDepartment] = useState("all") const [selectedRole, setSelectedRole] = useState("all") const [selectedStatus, setSelectedStatus] = useState("all") const [selectedUser, setSelectedUser] = useState(null) const [showUserDetail, setShowUserDetail] = useState(false) const [showInviteUser, setShowInviteUser] = useState(false) const [showEditUser, setShowEditUser] = useState(false) const [showDeleteConfirm, setShowDeleteConfirm] = useState(false) const [showInvitationLink, setShowInvitationLink] = useState(false) const [userToDelete, setUserToDelete] = useState(null) const [generatedInvitation, setGeneratedInvitation] = useState(null) const [isLoading, setIsLoading] = useState(false) const [success, setSuccess] = useState("") const [error, setError] = useState("") const [stats, setStats] = useState({ total: 0, admin: 0, developer: 0, user: 0, today: 0, totalApps: 0, totalReviews: 0 }) // 載入用戶資料 useEffect(() => { const fetchUsers = async () => { try { setIsLoading(true) // 獲取用戶列表 const usersResponse = await fetch('/api/users', { headers: { 'Authorization': `Bearer ${localStorage.getItem('token')}` } }) if (usersResponse.ok) { const usersData = await usersResponse.json() setUsers(usersData.users || []) } else { console.error('獲取用戶列表失敗') } // 獲取統計資料 const statsResponse = await fetch('/api/users/stats', { headers: { 'Authorization': `Bearer ${localStorage.getItem('token')}` } }) if (statsResponse.ok) { const statsData = await statsResponse.json() setStats(statsData) } else { console.error('獲取統計資料失敗') } } catch (error) { console.error('載入用戶資料失敗:', error) setError('載入用戶資料失敗') } finally { setIsLoading(false) } } fetchUsers() }, []) // 邀請用戶表單狀態 - 包含電子郵件和預設角色 const [inviteEmail, setInviteEmail] = useState("") const [inviteRole, setInviteRole] = useState("user") // 編輯用戶表單狀態 const [editUser, setEditUser] = useState({ id: "", name: "", email: "", department: "", role: "", status: "", }) const filteredUsers = users.filter((user) => { const matchesSearch = user.name.toLowerCase().includes(searchTerm.toLowerCase()) || user.email.toLowerCase().includes(searchTerm.toLowerCase()) const matchesDepartment = selectedDepartment === "all" || user.department === selectedDepartment const matchesRole = selectedRole === "all" || user.role === selectedRole || (user.status === "invited" && (user as any).invitedRole === selectedRole) const matchesStatus = selectedStatus === "all" || user.status === selectedStatus return matchesSearch && matchesDepartment && matchesRole && matchesStatus }) const handleViewUser = (user: any) => { setSelectedUser(user) setShowUserDetail(true) } const handleEditUser = (user: any) => { setEditUser({ id: user.id, name: user.name, email: user.email, department: user.department, role: user.role, status: user.status, }) setShowEditUser(true) } const handleDeleteUser = (user: any) => { setUserToDelete(user) setShowDeleteConfirm(true) } const handleToggleUserStatus = async (userId: string) => { setIsLoading(true) // 模擬 API 調用 await new Promise((resolve) => setTimeout(resolve, 1000)) setUsers( users.map((user) => user.id === userId ? { ...user, status: user.status === "active" ? "inactive" : "active" } : user, ), ) setIsLoading(false) setSuccess("用戶狀態更新成功!") setTimeout(() => setSuccess(""), 3000) } const handleChangeUserRole = async (userId: string, newRole: string) => { setIsLoading(true) // 模擬 API 調用 await new Promise((resolve) => setTimeout(resolve, 1000)) setUsers(users.map((user) => (user.id === userId ? { ...user, role: newRole } : user))) setIsLoading(false) setSuccess(`用戶權限已更新為${getRoleText(newRole)}!`) setTimeout(() => setSuccess(""), 3000) } const handleGenerateInvitation = async () => { setError("") // 驗證表單 if (!inviteEmail) { setError("請輸入電子郵件") return } // 檢查電子郵件格式 const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/ if (!emailRegex.test(inviteEmail)) { setError("請輸入有效的電子郵件格式") return } // 檢查電子郵件是否已存在 if (users.some((user) => user.email === inviteEmail)) { setError("此電子郵件已被使用或已發送邀請") return } setIsLoading(true) // 模擬生成邀請連結 await new Promise((resolve) => setTimeout(resolve, 1500)) // 生成邀請 token(實際應用中會由後端生成) const invitationToken = Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15) const invitationLink = `${window.location.origin}/register?token=${invitationToken}&email=${encodeURIComponent(inviteEmail)}&role=${inviteRole}` const newInvitation = { id: Date.now().toString(), name: "", email: inviteEmail, department: "", role: "", status: "invited", joinDate: "", lastLogin: "", totalApps: 0, totalReviews: 0, totalLikes: 0, invitationSentAt: new Date().toLocaleString("zh-TW", { year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", }), invitationLink: invitationLink, invitedRole: inviteRole, // 記錄邀請時的預設角色 } setUsers([...users, newInvitation]) setGeneratedInvitation(newInvitation) setInviteEmail("") setInviteRole("user") setIsLoading(false) setShowInviteUser(false) setShowInvitationLink(true) } const handleCopyInvitationLink = async (link: string) => { try { await navigator.clipboard.writeText(link) setSuccess("邀請連結已複製到剪貼簿!") setTimeout(() => setSuccess(""), 3000) } catch (err) { setError("複製失敗,請手動複製連結") setTimeout(() => setError(""), 3000) } } const handleRegenerateInvitation = async (userId: string, email: string) => { setIsLoading(true) // 模擬重新生成邀請連結 await new Promise((resolve) => setTimeout(resolve, 1500)) const newToken = Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15) const user = users.find((u) => u.id === userId) const role = (user as any)?.invitedRole || "user" const newInvitationLink = `${window.location.origin}/register?token=${newToken}&email=${encodeURIComponent(email)}&role=${role}` setUsers( users.map((user) => user.id === userId ? { ...user, invitationLink: newInvitationLink, invitationSentAt: new Date().toLocaleString("zh-TW", { year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", }), } : user, ), ) setIsLoading(false) setSuccess(`${email} 的邀請連結已重新生成!`) setTimeout(() => setSuccess(""), 3000) } const handleUpdateUser = async () => { setError("") if (!editUser.name || !editUser.email) { setError("請填寫所有必填欄位") return } // 檢查電子郵件是否被其他用戶使用 if (users.some((user) => user.email === editUser.email && user.id !== editUser.id)) { setError("此電子郵件已被其他用戶使用") return } setIsLoading(true) // 模擬 API 調用 await new Promise((resolve) => setTimeout(resolve, 1500)) setUsers(users.map((user) => (user.id === editUser.id ? { ...user, ...editUser } : user))) setIsLoading(false) setShowEditUser(false) setSuccess("用戶資料更新成功!") setTimeout(() => setSuccess(""), 3000) } const confirmDeleteUser = async () => { if (!userToDelete) return setIsLoading(true) // 模擬 API 調用 await new Promise((resolve) => setTimeout(resolve, 1500)) setUsers(users.filter((user) => user.id !== userToDelete.id)) setIsLoading(false) setShowDeleteConfirm(false) setUserToDelete(null) setSuccess("用戶刪除成功!") setTimeout(() => setSuccess(""), 3000) } const getRoleColor = (role: string) => { switch (role) { case "admin": return "bg-purple-100 text-purple-800 border-purple-200" case "developer": return "bg-green-100 text-green-800 border-green-200" case "user": return "bg-blue-100 text-blue-800 border-blue-200" default: return "bg-gray-100 text-gray-800 border-gray-200" } } const getStatusColor = (status: string) => { switch (status) { case "active": return "bg-green-100 text-green-800 border-green-200" case "inactive": return "bg-gray-100 text-gray-800 border-gray-200" case "invited": return "bg-yellow-100 text-yellow-800 border-yellow-200" default: return "bg-gray-100 text-gray-800 border-gray-200" } } const getStatusText = (status: string) => { switch (status) { case "active": return "活躍" case "inactive": return "非活躍" case "invited": return "已邀請" default: return status } } const getRoleText = (role: string) => { switch (role) { case "admin": return "管理員" case "developer": return "開發者" case "user": return "一般用戶" default: return "待設定" } } const getRoleIcon = (role: string) => { switch (role) { case "admin": return case "developer": return case "user": return default: return } } return (
{/* Success/Error Messages */} {success && ( {success} )} {error && ( {error} )} {/* Header */}

用戶管理

管理平台用戶和權限

{/* Stats Cards */}

總用戶數

{stats.total}

活躍用戶

{stats.total}

管理員

{stats.admin}

開發者

{stats.developer}

一般用戶

{stats.user}

今日新增

{stats.today}

應用

{stats.totalApps}

評價

{stats.totalReviews}

{/* Filters */}
setSearchTerm(e.target.value)} className="pl-10" />
{/* Users Table */} 用戶列表 ({filteredUsers.length}) 管理所有平台用戶 {isLoading ? (
載入用戶資料中...
) : filteredUsers.length === 0 ? (

沒有找到用戶

嘗試調整搜尋條件或篩選器

) : ( 用戶 部門 角色 狀態 加入日期 最後登入 統計 操作 {filteredUsers.map((user) => (
{user.name ? user.name.charAt(0) : user.email.charAt(0).toUpperCase()}

{user.name || "待註冊"}

{user.email}

{user.status === "invited" && user.invitationSentAt && (

邀請已生成:{user.invitationSentAt}

)}
{user.department || "待設定"}
{getRoleIcon(user.role || (user as any).invitedRole)} {getRoleText(user.role || (user as any).invitedRole)}
{getStatusText(user.status)} {user.joinDate || "-"} {user.lastLogin || "-"}

{user.totalApps} 應用

{user.totalReviews} 評價

handleViewUser(user)}> 查看詳情 {user.status !== "invited" && ( handleEditUser(user)}> 編輯用戶 )} {user.status === "invited" && user.invitationLink && ( <> handleCopyInvitationLink(user.invitationLink)}> 複製邀請連結 handleRegenerateInvitation(user.id, user.email)}> 重新生成連結 )} {user.status !== "invited" && user.role && ( handleToggleUserStatus(user.id)}> {user.status === "active" ? "停用用戶" : "啟用用戶"} )} handleDeleteUser(user)} className="text-red-600"> 刪除用戶
))}
)}
{/* Invite User Dialog - 包含角色選擇 */} 邀請用戶 生成邀請連結,手動分享給新用戶
setInviteEmail(e.target.value)} placeholder="請輸入電子郵件" className="pl-10" />

用戶註冊時將自動設定為此角色

邀請流程說明:

系統將生成專屬邀請連結,您可以複製連結並手動分享給用戶。用戶點擊連結後可自行設定姓名、部門、密碼並完成註冊。

角色權限說明:

  • 一般用戶:只能瀏覽和收藏應用
  • 開發者:可以提交應用申請
  • 管理員:可以訪問管理後台
{/* Invitation Link Dialog */} 邀請連結已生成 請複製以下連結並分享給用戶 {generatedInvitation && (
{generatedInvitation.email.charAt(0).toUpperCase()}

{generatedInvitation.email}

{getRoleIcon(generatedInvitation.invitedRole)} {getRoleText(generatedInvitation.invitedRole)}

生成時間:{generatedInvitation.invitationSentAt}

注意事項:

  • 請將此連結安全地分享給指定用戶
  • 連結包含用戶的電子郵件和角色資訊
  • 用戶將自動設定為{getRoleText(generatedInvitation.invitedRole)}角色
  • 如需重新生成連結,可在用戶列表中操作
)}
{/* Edit User Dialog */} 編輯用戶 修改用戶資料和權限
setEditUser({ ...editUser, name: e.target.value })} className="pl-10" />
setEditUser({ ...editUser, email: e.target.value })} className="pl-10" />
{/* Delete Confirmation Dialog */} 確認刪除用戶 此操作無法復原。確定要刪除用戶「{userToDelete?.name || userToDelete?.email}」嗎?
{/* User Detail Dialog */} 用戶詳情 查看用戶的詳細資訊和活動記錄 {selectedUser && ( 基本資訊 活動記錄 統計數據
{selectedUser.name ? selectedUser.name.charAt(0) : selectedUser.email.charAt(0).toUpperCase()}

{selectedUser.name || "待註冊用戶"}

{selectedUser.email}

{getRoleIcon(selectedUser.role || (selectedUser as any).invitedRole)} {getRoleText(selectedUser.role || (selectedUser as any).invitedRole)}
{getStatusText(selectedUser.status)}

部門

{selectedUser.department || "待設定"}

加入日期

{selectedUser.joinDate || "尚未註冊"}

最後登入

{selectedUser.lastLogin || "尚未登入"}

用戶ID

{selectedUser.id}

{selectedUser.status === "invited" && selectedUser.invitationSentAt && ( <>

邀請生成時間

{selectedUser.invitationSentAt}

邀請狀態

等待用戶註冊

)}
{selectedUser.status === "invited" && selectedUser.invitationLink && (
)}
{selectedUser.status === "invited" ? (

用戶尚未註冊,暫無活動記錄

) : (

登入系統

2024-01-20 16:45

查看應用:智能對話助手

2024-01-20 15:30

)}

{selectedUser.totalApps}

創建應用

{selectedUser.totalReviews}

撰寫評價

{selectedUser.totalLikes}

獲得讚數

{selectedUser.status === "invited" ? 0 : 15}

登入天數

)}
) }