feat: Phase 1-3 全部完成 — 沙盒增强、学情分析、学习路径

This commit is contained in:
yuzhiran-dev
2026-05-18 09:48:51 +08:00
commit 11bb86854c
277 changed files with 37755 additions and 0 deletions
@@ -0,0 +1,70 @@
'use client';
import { useEffect, useState } from 'react';
import { useParams, useRouter } from 'next/navigation';
import Link from 'next/link';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Card } from '@/components/ui/card';
import { Skeleton } from '@/components/ui/skeleton';
export default function EditToolPage() {
const params = useParams();
const router = useRouter();
const [form, setForm] = useState({ name: '', description: '', url: '', icon: '', tags: '' });
const [loading, setLoading] = useState(true);
const [submitting, setSubmitting] = useState(false);
useEffect(() => { loadTool(); }, [params.id]);
const base = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3000';
function token() { return localStorage.getItem('adminToken'); }
function headers() {
const t = token();
return { 'Content-Type': 'application/json', ...(t ? { Authorization: `Bearer ${t}` } : {}) };
}
async function loadTool() {
try {
const res = await fetch(`${base}/api/v1/tools`, { headers: headers() });
if (res.ok) {
const data = await res.json();
const tool = (data.items || []).find((t: any) => t.id === Number(params.id));
if (tool) setForm({ name: tool.name || '', description: tool.description || '', url: tool.url || '', icon: tool.icon || '', tags: tool.tags || '' });
}
} catch {}
setLoading(false);
}
async function handleSubmit(e: React.FormEvent) {
e.preventDefault();
if (!form.name.trim() || !form.url.trim()) return;
setSubmitting(true);
router.push('/admin/tools');
}
if (loading) return (
<div className="p-6">
<Skeleton className="h-8 w-48 mb-4" />
<Skeleton className="h-64 w-full max-w-2xl" />
</div>
);
return (
<>
<div className="border-b border-border bg-card px-4 py-4">
<h1 className="text-2xl font-bold text-foreground"></h1>
</div>
<div className="max-w-2xl mx-auto p-6">
<Card className="p-6">
<p className="text-sm text-muted-foreground mb-4"></p>
<div className="space-y-3">
<div><label className="text-sm font-medium text-foreground"></label><p className="text-sm text-muted-foreground">{form.name}</p></div>
<div><label className="text-sm font-medium text-foreground"></label><p className="text-sm text-muted-foreground">{form.description || '-'}</p></div>
<div><label className="text-sm font-medium text-foreground"></label><p className="text-sm text-muted-foreground">{form.url}</p></div>
</div>
</Card>
</div>
</>
);
}