From c5a48807e5fc4f5acb8518b57bba867af4e71171 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=90=B3=E4=BD=A9=E5=BA=AD?= Date: Sat, 4 Oct 2025 21:53:50 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=B8=AC=E9=A9=97=E9=80=A3?= =?UTF-8?q?=E7=B5=90=E7=AE=A1=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/admin/test-links/page.tsx | 435 ++++++++++++++++++++++++++++++++++ app/home/page.tsx | 10 +- 2 files changed, 444 insertions(+), 1 deletion(-) create mode 100644 app/admin/test-links/page.tsx diff --git a/app/admin/test-links/page.tsx b/app/admin/test-links/page.tsx new file mode 100644 index 0000000..e3494f1 --- /dev/null +++ b/app/admin/test-links/page.tsx @@ -0,0 +1,435 @@ +"use client" + +import { useState, useEffect } from "react" +import { ProtectedRoute } from "@/components/protected-route" +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card" +import { Button } from "@/components/ui/button" +import { Input } from "@/components/ui/input" +import { Label } from "@/components/ui/label" +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select" +import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table" +import { Badge } from "@/components/ui/badge" +import { Alert, AlertDescription } from "@/components/ui/alert" +import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs" +import { + ArrowLeft, + Copy, + CheckCircle, + Clock, + Users, + Link as LinkIcon, + Send, + RefreshCw, + Eye, + Trash2, + Plus, + Loader2, +} from "lucide-react" +import Link from "next/link" + +// 定義測驗連結類型 +interface TestLink { + id: string + name: string + type: 'logic' | 'creative' | 'combined' + url: string + createdAt: string + expiresAt?: string + isActive: boolean + totalSent: number + completedCount: number + pendingCount: number +} + +// 定義已送出連結的狀態 +interface SentLinkStatus { + id: string + linkId: string + recipientName: string + recipientEmail: string + sentAt: string + status: 'pending' | 'completed' | 'expired' + completedAt?: string + testType: 'logic' | 'creative' | 'combined' + score?: number +} + +export default function TestLinksPage() { + const [currentLinks, setCurrentLinks] = useState([]) + const [sentLinks, setSentLinks] = useState([]) + const [loading, setLoading] = useState(true) + const [newLinkName, setNewLinkName] = useState("") + const [newLinkType, setNewLinkType] = useState<'logic' | 'creative' | 'combined'>('combined') + const [showCreateForm, setShowCreateForm] = useState(false) + + // 模擬數據 + useEffect(() => { + const mockCurrentLinks: TestLink[] = [ + { + id: '1', + name: '2024年度綜合能力測驗', + type: 'combined', + url: 'https://hr-assessment.com/test/combined/abc123', + createdAt: '2024-01-15T10:00:00Z', + expiresAt: '2024-12-31T23:59:59Z', + isActive: true, + totalSent: 45, + completedCount: 38, + pendingCount: 7 + }, + { + id: '2', + name: '創意能力專項測驗', + type: 'creative', + url: 'https://hr-assessment.com/test/creative/def456', + createdAt: '2024-01-20T14:30:00Z', + isActive: true, + totalSent: 23, + completedCount: 20, + pendingCount: 3 + } + ] + + const mockSentLinks: SentLinkStatus[] = [ + { + id: '1', + linkId: '1', + recipientName: '張小明', + recipientEmail: 'zhang.xiaoming@company.com', + sentAt: '2024-01-15T10:30:00Z', + status: 'completed', + completedAt: '2024-01-16T09:15:00Z', + testType: 'combined', + score: 85 + }, + { + id: '2', + linkId: '1', + recipientName: '李美華', + recipientEmail: 'li.meihua@company.com', + sentAt: '2024-01-15T11:00:00Z', + status: 'completed', + completedAt: '2024-01-17T14:20:00Z', + testType: 'combined', + score: 92 + }, + { + id: '3', + linkId: '1', + recipientName: '王大偉', + recipientEmail: 'wang.dawei@company.com', + sentAt: '2024-01-15T11:30:00Z', + status: 'pending', + testType: 'combined' + }, + { + id: '4', + linkId: '2', + recipientName: '陳小芳', + recipientEmail: 'chen.xiaofang@company.com', + sentAt: '2024-01-20T15:00:00Z', + status: 'completed', + completedAt: '2024-01-21T10:45:00Z', + testType: 'creative', + score: 78 + } + ] + + setTimeout(() => { + setCurrentLinks(mockCurrentLinks) + setSentLinks(mockSentLinks) + setLoading(false) + }, 1000) + }, []) + + const handleCopyLink = (url: string) => { + navigator.clipboard.writeText(url) + // 這裡可以添加 toast 提示 + } + + const handleCreateLink = () => { + if (!newLinkName.trim()) return + + const newLink: TestLink = { + id: Date.now().toString(), + name: newLinkName, + type: newLinkType, + url: `https://hr-assessment.com/test/${newLinkType}/${Math.random().toString(36).substr(2, 9)}`, + createdAt: new Date().toISOString(), + isActive: true, + totalSent: 0, + completedCount: 0, + pendingCount: 0 + } + + setCurrentLinks([...currentLinks, newLink]) + setNewLinkName("") + setShowCreateForm(false) + } + + const getStatusBadge = (status: string) => { + switch (status) { + case 'completed': + return 已完成 + case 'pending': + return 進行中 + case 'expired': + return 已過期 + default: + return 未知 + } + } + + const getTypeName = (type: string) => { + switch (type) { + case 'logic': + return '邏輯思維' + case 'creative': + return '創意能力' + case 'combined': + return '綜合能力' + default: + return '未知' + } + } + + if (loading) { + return ( +
+
+
+ +
+
+
+ ) + } + + return ( +
+ {/* Header */} +
+
+
+ +
+ +
+
+

測驗連結管理

+

+ 管理測驗連結的發送和追蹤測試完成狀態 +

+
+
+
+
+ +
+
+ + + 目前測驗連結 + 已送出連結狀態 + + + {/* 目前測驗連結 */} + + + +
+
+ 目前測驗連結 + + 管理當前可用的測驗連結 + +
+ +
+
+ + {/* 新增連結表單 */} + {showCreateForm && ( + + + 新增測驗連結 + + +
+ + setNewLinkName(e.target.value)} + placeholder="請輸入連結名稱" + /> +
+
+ + +
+
+ + +
+
+
+ )} + + {/* 連結列表 */} +
+ {currentLinks.map((link) => ( + + +
+
+
+

{link.name}

+ + {link.isActive ? "啟用中" : "已停用"} + + {getTypeName(link.type)} +
+
+ 建立時間: {new Date(link.createdAt).toLocaleString('zh-TW')} + {link.expiresAt && ( + 到期時間: {new Date(link.expiresAt).toLocaleString('zh-TW')} + )} +
+
+ + + 總發送: {link.totalSent} + + + + 已完成: {link.completedCount} + + + + 進行中: {link.pendingCount} + +
+
+
+ + +
+
+
+
+ ))} +
+
+
+
+ + {/* 已送出連結狀態 */} + + + + 已送出連結狀態清單 + + 追蹤已送出測驗連結的完成狀態 + + + + + + + 收件人 + 測驗類型 + 發送時間 + 狀態 + 完成時間 + 分數 + 操作 + + + + {sentLinks.map((sentLink) => ( + + +
+
{sentLink.recipientName}
+
{sentLink.recipientEmail}
+
+
+ + {getTypeName(sentLink.testType)} + + + {new Date(sentLink.sentAt).toLocaleString('zh-TW')} + + + {getStatusBadge(sentLink.status)} + + + {sentLink.completedAt + ? new Date(sentLink.completedAt).toLocaleString('zh-TW') + : '-' + } + + + {sentLink.score ? `${sentLink.score}分` : '-'} + + +
+ + {sentLink.status === 'pending' && ( + + )} +
+
+
+ ))} +
+
+
+
+
+
+
+
+
+ ) +} diff --git a/app/home/page.tsx b/app/home/page.tsx index e409128..b44fc9d 100644 --- a/app/home/page.tsx +++ b/app/home/page.tsx @@ -3,7 +3,7 @@ import { useState, useEffect, useRef } from "react" import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card" import { Button } from "@/components/ui/button" -import { Brain, Lightbulb, BarChart3, Users, Settings, Menu, ChevronDown } from "lucide-react" +import { Brain, Lightbulb, BarChart3, Users, Settings, Menu, ChevronDown, Link as LinkIcon } from "lucide-react" import { Sheet, SheetContent, SheetHeader, SheetTitle, SheetTrigger } from "@/components/ui/sheet" import Link from "next/link" import Image from "next/image" @@ -123,6 +123,14 @@ export default function HomePage() { 題目管理 + setIsDropdownOpen(false)} + > + + 測驗連結 + )}