"use client"; // @/components/index.tsx import { useState, useEffect } from "react"; import { motion, AnimatePresence } from "framer-motion"; import { Plus, Check, RotateCcw, Download, Upload, Trash2, Edit2, Save, X, } from "lucide-react"; 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 { useToast } from "@/components/ui/use-toast"; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger, } from "@/components/ui/dialog"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import Toast from "@/components/ui/toast"; // 确保导入 Toast 组件 interface ChecklistItem { id: string; text: string; completed: boolean; } interface Checklist { id: string; name: string; items: ChecklistItem[]; } interface ToastOptions { title: string; description?: string; variant?: "default" | "destructive"; } export function CombinedChecklistAppComponent() { const [checklists, setChecklists] = useState([]); const [currentChecklist, setCurrentChecklist] = useState(""); const [newItemText, setNewItemText] = useState(""); const [newChecklistName, setNewChecklistName] = useState(""); const [editingId, setEditingId] = useState(null); const [editName, setEditName] = useState(""); const { toasts, showToast } = useToast(); // 使用 toasts 状态 useEffect(() => { const savedChecklists = localStorage.getItem("checklists"); if (savedChecklists) { setChecklists(JSON.parse(savedChecklists)); } }, []); useEffect(() => { localStorage.setItem("checklists", JSON.stringify(checklists)); }, [checklists]); const addChecklist = () => { if (newChecklistName.trim() === "") return; const newChecklist: Checklist = { id: Date.now().toString(), name: newChecklistName, items: [], }; setChecklists([...checklists, newChecklist]); setNewChecklistName(""); setCurrentChecklist(newChecklist.id); showToast({ title: "新检查单已创建", description: `"${newChecklistName}" 已添加到您的检查单列表。`, } as ToastOptions); }; const addItem = () => { if (newItemText.trim() === "" || currentChecklist === "") return; const newItem: ChecklistItem = { id: Date.now().toString(), text: newItemText, completed: false, }; setChecklists( checklists.map((list) => list.id === currentChecklist ? { ...list, items: [...list.items, newItem] } : list ) ); setNewItemText(""); }; const toggleItem = (itemId: string) => { setChecklists( checklists.map((list) => list.id === currentChecklist ? { ...list, items: list.items.map((item) => item.id === itemId ? { ...item, completed: !item.completed } : item ), } : list ) ); }; const deleteItem = (itemId: string) => { setChecklists( checklists.map((list) => list.id === currentChecklist ? { ...list, items: list.items.filter((item) => item.id !== itemId), } : list ) ); showToast({ title: "检查项已删除", description: "该项目已从您的检查单中移除。", } as ToastOptions); }; const resetChecklist = () => { setChecklists( checklists.map((list) => list.id === currentChecklist ? { ...list, items: list.items.map((item) => ({ ...item, completed: false })), } : list ) ); showToast({ title: "检查单已重置", description: "所有项目已标记为未完成。", } as ToastOptions); }; const exportData = () => { const dataStr = JSON.stringify(checklists); const dataUri = "data:application/json;charset=utf-8," + encodeURIComponent(dataStr); const exportFileDefaultName = "checklists.json"; const linkElement = document.createElement("a"); linkElement.setAttribute("href", dataUri); linkElement.setAttribute("download", exportFileDefaultName); linkElement.click(); showToast({ title: "数据已导出", description: "您的检查单数据已成功导出为 JSON 文件。", } as ToastOptions); }; const importData = (event: React.ChangeEvent) => { const file = event.target.files?.[0]; if (file) { const reader = new FileReader(); reader.onload = (e) => { const content = e.target?.result; if (typeof content === "string") { try { const importedChecklists = JSON.parse(content); setChecklists(importedChecklists); showToast({ title: "数据导入成功", description: "您的检查单已成功导入。", } as ToastOptions); } catch { showToast({ title: "导入失败", description: "无法解析导入的文件。请确保它是有效的 JSON 格式。", variant: "destructive", } as ToastOptions); } } }; reader.readAsText(file); } }; const startEditing = (id: string, name: string) => { setEditingId(id); setEditName(name); }; const saveEdit = (id: string) => { setChecklists( checklists.map((list) => list.id === id ? { ...list, name: editName } : list ) ); setEditingId(null); showToast({ title: "检查单已更新", description: `检查单名称已更改为 "${editName}"。`, } as ToastOptions); }; const cancelEdit = () => { setEditingId(null); setEditName(""); }; const deleteChecklist = (id: string) => { setChecklists(checklists.filter((list) => list.id !== id)); if (currentChecklist === id) { setCurrentChecklist(""); } showToast({ title: "检查单已删除", description: "该检查单及其所有项目已被移除。", variant: "destructive", } as ToastOptions); }; return (
检查单应用 检查单 管理检查单
setNewChecklistName(e.target.value)} placeholder="输入检查单名称" className="mr-2 flex-grow" />
{currentChecklist && (
setNewItemText(e.target.value)} placeholder="输入新的检查项" className="mr-2 flex-grow" />
{checklists .find((list) => list.id === currentChecklist) ?.items.map((item) => ( toggleItem(item.id)} whileHover={{ scale: 1.1 }} whileTap={{ scale: 0.9 }} > {item.completed && ( )} {item.text} deleteItem(item.id)} className="text-destructive hover:text-destructive/90 p-1 rounded-full" whileHover={{ scale: 1.1 }} whileTap={{ scale: 0.9 }} > ))}
)}
{checklists.map((checklist) => ( {editingId === checklist.id ? (
setEditName(e.target.value)} className="flex-grow" placeholder="输入新的检查单名称" />
) : (
{checklist.name}
确认删除

您确定要删除 "{checklist.name}" 检查单吗?此操作无法撤销。

)}

共 {checklist.items.length} 个项目, { checklist.items.filter((item) => item.completed).length }{" "} 个已完成

))}
{checklists.length === 0 && ( 暂无检查单。请在检查单标签页创建新的检查单。 )}
{/* Toast 组件 */}
{toasts.map((toast) => ( ))}
); }