diff --git a/.gitignore b/.gitignore index 9b1913e..ab72c11 100644 --- a/.gitignore +++ b/.gitignore @@ -34,3 +34,5 @@ yarn-error.log* # typescript *.tsbuildinfo next-env.d.ts + +.trae diff --git a/app/admin/metrics/page.tsx b/app/admin/metrics/page.tsx index 0a86390..08dd68c 100644 --- a/app/admin/metrics/page.tsx +++ b/app/admin/metrics/page.tsx @@ -18,6 +18,16 @@ import type { Metric } from '@/types/database'; import { toast } from 'sonner'; import { Plus, Pencil, Trash2, Gauge, Loader2, TrendingUp, TrendingDown } from 'lucide-react'; import { getErrorMessage } from '@/lib/error-utils'; +import { + AlertDialog, + AlertDialogAction, + AlertDialogCancel, + AlertDialogContent, + AlertDialogDescription, + AlertDialogFooter, + AlertDialogHeader, + AlertDialogTitle, +} from '@/components/ui/alert-dialog'; const metricSchema = z.object({ name: z.string().min(1, '名称不能为空'), @@ -35,6 +45,9 @@ export default function AdminMetricsPage() { const [isDialogOpen, setIsDialogOpen] = useState(false); const [editingMetric, setEditingMetric] = useState(null); const [isSubmitting, setIsSubmitting] = useState(false); + const [deleteMetricId, setDeleteMetricId] = useState(null); + const [isDeleteOpen, setIsDeleteOpen] = useState(false); + const [isDeleting, setIsDeleting] = useState(false); const form = useForm({ resolver: zodResolver(metricSchema), @@ -121,17 +134,26 @@ export default function AdminMetricsPage() { } }; - const handleDelete = async (metricId: string) => { - if (!confirm('确定要删除此指标吗?')) return; + const requestDelete = (metricId: string) => { + setDeleteMetricId(metricId); + setIsDeleteOpen(true); + }; + const confirmDelete = async () => { + if (!deleteMetricId) return; + setIsDeleting(true); try { - const res = await fetch(`/api/metrics/${metricId}`, { method: 'DELETE' }); + const res = await fetch(`/api/metrics/${deleteMetricId}`, { method: 'DELETE' }); if (!res.ok) throw new Error('删除失败'); toast.success('指标已删除'); fetchMetrics(); } catch (error) { toast.error(getErrorMessage(error)); + } finally { + setIsDeleting(false); + setIsDeleteOpen(false); + setDeleteMetricId(null); } }; @@ -309,7 +331,7 @@ export default function AdminMetricsPage() { - @@ -327,6 +349,27 @@ export default function AdminMetricsPage() { + + + + + 确认删除指标? + + 删除后无法恢复。 + + + + 取消 + + {isDeleting ? '删除中...' : '确认删除'} + + + + ); } diff --git a/app/admin/templates/page.tsx b/app/admin/templates/page.tsx index 80ee337..102ec82 100644 --- a/app/admin/templates/page.tsx +++ b/app/admin/templates/page.tsx @@ -18,6 +18,16 @@ import type { Template } from '@/types/database'; import { toast } from 'sonner'; import { Plus, Pencil, Trash2, Files, Loader2, X } from 'lucide-react'; import { getErrorMessage } from '@/lib/error-utils'; +import { + AlertDialog, + AlertDialogAction, + AlertDialogCancel, + AlertDialogContent, + AlertDialogDescription, + AlertDialogFooter, + AlertDialogHeader, + AlertDialogTitle, +} from '@/components/ui/alert-dialog'; const templateItemSchema = z.object({ title: z.string().min(1, '标题不能为空'), @@ -44,6 +54,9 @@ export default function AdminTemplatesPage() { const [isDialogOpen, setIsDialogOpen] = useState(false); const [editingTemplate, setEditingTemplate] = useState